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