1 /** 2 * 3 * TODO: description 4 * 5 * This file is a part of USB SCSI CAM for Haiku OS. 6 * May be used under terms of the MIT License 7 * 8 * Author(s): 9 * Siarzhuk Zharski <imker@gmx.li> 10 * 11 * 12 */ 13 #include <string.h> 14 15 #include "usb_scsi.h" 16 17 #include "device_info.h" 18 #include "proto_common.h" 19 #include "tracing.h" 20 #include "usb_defs.h" 21 #include "scsi_commands.h" 22 23 /** 24 \fn:bulk_callback 25 \param cookie:??? 26 \param status:??? 27 \param data:??? 28 \param actual_len:??? 29 \return:??? 30 31 ??? 32 */ 33 void bulk_callback(void *cookie, status_t status, void* data, uint32 actual_len) 34 { 35 TRACE_BULK_CALLBACK(status, actual_len); 36 if(cookie){ 37 usb_device_info *udi = (usb_device_info *)cookie; 38 udi->status = status; 39 udi->data = data; 40 udi->actual_len = actual_len; 41 if(udi->status != B_CANCELED) 42 release_sem(udi->trans_sem); 43 } 44 } 45 46 /** 47 \fn:exec_io 48 \param udi: ??? 49 \return:??? 50 51 ??? 52 */ 53 status_t process_data_io(usb_device_info *udi, //sg_buffer *sgb, 54 iovec *sg_data, int32 sg_count, EDirection dir) 55 { 56 status_t status = B_OK; 57 usb_pipe pipe = (dir == eDirIn) ? udi->pipe_in : udi->pipe_out; 58 // TRACE_DATA_IO_SG(data_sg, sglist_count); 59 status = (*udi->usb_m->queue_bulk_v)(pipe, sg_data, sg_count, bulk_callback, udi); 60 if(status == B_OK){ 61 status = acquire_sem_etc(udi->trans_sem, 1, B_RELATIVE_TIMEOUT, udi->trans_timeout/*LOCK_TIMEOUT*/); 62 if(status == B_OK){ 63 status = udi->status; 64 if(udi->status == B_DEV_STALLED){ 65 status_t st=(*udi->usb_m->clear_feature)(pipe, USB_FEATURE_ENDPOINT_HALT); 66 TRACE_ALWAYS("clear_on_STALL:%08x\n",st); 67 } 68 }else{ 69 TRACE_ALWAYS("process_data_io:acquire_sem failed:%08x\n", status); 70 (*udi->usb_m->cancel_queued_transfers)(pipe); 71 } 72 } else { 73 TRACE_ALWAYS("process_data_io:queue_bulk_v failed:%08x\n", status); 74 } 75 TRACE_DATA_IO("process_data_io:processed:%d;status:%08x\n", udi->actual_len, status); 76 return status; 77 } 78 79 void transfer_callback(struct _usb_device_info *udi, CCB_SCSIIO *ccbio, 80 int32 residue, status_t status) 81 { 82 ccbio->cam_resid = residue; 83 switch(status){ 84 case B_OK: 85 ccbio->cam_ch.cam_status = CAM_REQ_CMP; 86 break; 87 case B_CMD_FAILED: 88 case B_CMD_UNKNOWN:{ 89 size_t sense_data_len = (0 != ccbio->cam_sense_len) ? 90 ccbio->cam_sense_len : SSD_MIN_SIZE; 91 uchar *sense_data_ptr = (NULL != ccbio->cam_sense_ptr) ? 92 ccbio->cam_sense_ptr : (uchar*)&udi->autosense_data; 93 uint8 lun = ((ccbio->cam_ch.cam_target_lun) << CMD_LUN_SHIFT) & CMD_LUN; 94 scsi_cmd_generic_6 cmd = { REQUEST_SENSE, {lun, 0}, sense_data_len, 0}; 95 /* transform command as required by protocol */ 96 uint8 *rcmd = udi->scsi_command_buf; 97 uint8 rcmdlen = sizeof(udi->scsi_command_buf); 98 iovec sense_sg = { sense_data_ptr, sense_data_len }; 99 TRACE("transfer_callback:requesting sense information " 100 "due status:%08x\n", status); 101 memset(&udi->autosense_data, 0, SSD_FULL_SIZE); /* just to be sure */ 102 if(B_OK != (*udi->transform_m->transform)(udi, (uint8 *)&cmd, sizeof(cmd), &rcmd, &rcmdlen)){ 103 TRACE_ALWAYS("transfer_callback: REQUEST SENSE command transform failed\n"); 104 ccbio->cam_ch.cam_status = CAM_IDE; //????????? 105 break; 106 } 107 /* transfer command to device. SCSI status will be handled in callback */ 108 (*udi->protocol_m->transfer)(udi, rcmd, rcmdlen, &sense_sg, 1, sense_data_len, 109 eDirIn, ccbio, sense_callback); 110 } 111 break; 112 case B_CMD_WIRE_FAILED: 113 ccbio->cam_ch.cam_status = CAM_REQ_CMP_ERR; 114 break; 115 default: 116 TRACE_ALWAYS("transfer_callback:unknown status:%08x\n", status); 117 ccbio->cam_ch.cam_status = CAM_IDE; 118 break; 119 } 120 } 121 122 void sense_callback(struct _usb_device_info *udi, CCB_SCSIIO *ccbio, 123 int32 residue, status_t status) 124 { 125 ccbio->cam_sense_resid = residue; 126 switch(status){ 127 case B_CMD_UNKNOWN: 128 case B_CMD_FAILED: 129 case B_OK:{ 130 bool b_own_data = (ccbio->cam_sense_ptr == NULL); 131 scsi_sense_data *sense_data = b_own_data ? 132 &udi->autosense_data : (scsi_sense_data *)ccbio->cam_sense_ptr; 133 int data_len = (ccbio->cam_sense_len != 0) ? ccbio->cam_sense_len : SSD_MIN_SIZE; 134 TRACE_SENSE_DATA((uint8*)sense_data, data_len); 135 if((sense_data->flags & SSD_KEY) == SSD_KEY_NO_SENSE){ 136 /* no problems. normal case for CB handling */ 137 TRACE("sense_callback: key OK\n"); 138 ccbio->cam_ch.cam_status = CAM_REQ_CMP; 139 } else { 140 if(!b_own_data){ /* we have used CCBIO provided buffer for sense data */ 141 TRACE("sense_callback:sense info OK????:%08x \n", sense_data); 142 ccbio->cam_ch.cam_status = CAM_REQ_CMP_ERR | CAM_AUTOSNS_VALID; 143 ccbio->cam_scsi_status = SCSI_STATUS_CHECK_CONDITION; 144 } else { 145 /*TODO: ?????????????????????????????????????? */ 146 ccbio->cam_ch.cam_status = CAM_REQ_CMP; 147 // ccbio->cam_ch.cam_status = CAM_REQ_CMP_ERR /*| CAM_AUTOSNS_VALID*/; 148 // ccbio->cam_scsi_status = SCSI_STATUS_CHECK_CONDITION; 149 TRACE("sense_callback: sense still not handled...\n"); 150 } 151 } 152 } 153 break; 154 default: 155 TRACE_ALWAYS("sense_callback:unknown status:%08x\n", status); 156 case B_CMD_WIRE_FAILED: 157 ccbio->cam_ch.cam_status = CAM_AUTOSENSE_FAIL; 158 break; 159 } 160 } 161 162