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 /** bulk-only protocol specific implementation */ 8 9 /* References: 10 * USB Mass Storage Class specifications: 11 * http://www.usb.org/developers/data/devclass/usbmassover_11.pdf [1] 12 * http://www.usb.org/developers/data/devclass/usbmassbulk_10.pdf [2] 13 */ 14 #include "usb_scsi.h" 15 16 #include "device_info.h" 17 18 #include "proto_module.h" 19 #include "proto_common.h" 20 #include "proto_bulk.h" 21 22 #include "usb_defs.h" 23 24 #include <string.h> /* strncpy */ 25 26 /*Bulk-Only protocol specifics*/ 27 #define USB_REQ_MS_RESET 0xff /* Bulk-Only reset */ 28 #define USB_REQ_MS_GET_MAX_LUN 0xfe /* Get maximum lun */ 29 30 /* Command Block Wrapper */ 31 typedef struct _usb_mass_CBW{ 32 uint32 signature; 33 uint32 tag; 34 uint32 data_transfer_len; 35 uint8 flags; 36 uint8 lun; 37 uint8 cdb_len; 38 #define CBW_CDB_LENGTH 16 39 uint8 CDB[CBW_CDB_LENGTH]; 40 } usb_mass_CBW; /*sizeof(usb_mass_CBW) must be 31*/ 41 #define CBW_LENGTH 0x1f 42 43 /* Command Status Wrapper */ 44 typedef struct _usb_mass_CSW{ 45 uint32 signature; 46 uint32 tag; 47 uint32 data_residue; 48 uint8 status; 49 } usb_mass_CSW; /*sizeof(usb_mass_CSW) must be 13*/ 50 #define CSW_LENGTH 0x0d 51 52 #define CSW_STATUS_GOOD 0x0 53 #define CSW_STATUS_FAILED 0x1 54 #define CSW_STATUS_PHASE 0x2 55 56 #define CBW_SIGNATURE 0x43425355 57 #define CSW_SIGNATURE 0x53425355 58 59 #define CBW_FLAGS_OUT 0x00 60 #define CBW_FLAGS_IN 0x80 61 62 /*=========================== tracing helpers ==================================*/ 63 void trace_CBW(usb_device_info *udi, const usb_mass_CBW *cbw) 64 { 65 char buf[sizeof(uint32) + 1] = {0}; 66 strncpy(buf, (char *)&cbw->signature, sizeof(uint32)); 67 PTRACE(udi, "\nCBW:{'%s'; tag:%d; data_len:%d; flags:0x%02x; lun:%d; cdb_len:%d;}\n", 68 buf, 69 cbw->tag, 70 cbw->data_transfer_len, 71 cbw->flags, 72 cbw->lun, 73 cbw->cdb_len); 74 udi->trace_bytes("CDB:\n", cbw->CDB, CBW_CDB_LENGTH); 75 } 76 77 void trace_CSW(usb_device_info *udi, const usb_mass_CSW *csw) 78 { 79 char buf[sizeof(uint32) + 1] = {0}; 80 strncpy(buf, (char *)&csw->signature, sizeof(uint32)); 81 PTRACE(udi, "CSW:{'%s'; tag:%d; residue:%d; status:0x%02x}\n", 82 buf, 83 csw->tag, 84 csw->data_residue, 85 csw->status); 86 } 87 88 /** 89 \fn:get_max_luns 90 \param udi: device for wich max LUN info is requested 91 \return:always B_OK - if info was not retrieved max LUN is defaulted to 0 92 93 tries to retrieve the maximal Logical Unit Number supported by 94 this device. If device doesn't support GET_MAX_LUN request - single LUN is 95 assumed. ([2] 3.2) 96 */ 97 static status_t 98 get_max_luns(usb_device_info *udi) 99 { 100 status_t status = B_OK; 101 udi->max_lun = 0; 102 if(!HAS_FIXES(udi->properties, FIX_NO_GETMAXLUN)){ 103 size_t len = 0; 104 if(B_OK != (status = (*udi->usb_m->send_request)(udi->device, 105 USB_REQTYPE_INTERFACE_IN | USB_REQTYPE_CLASS, 106 USB_REQ_MS_GET_MAX_LUN, 0x0, udi->interface, 107 0x1, &udi->max_lun, &len))) 108 { 109 if(status == B_DEV_STALLED){ 110 PTRACE_ALWAYS(udi, "get_max_luns[%d]:not supported. " 111 "Assuming single LUN available.\n", udi->dev_num); 112 } else { 113 PTRACE(udi, "get_max_luns[%d]:failed(%08x)." 114 "Assuming single LUN available.\n", udi->dev_num, status); 115 } 116 udi->max_lun = 0; 117 status = B_OK; 118 } /* else - all is OK - max luns info readed */ 119 } 120 return status; 121 } 122 /** 123 \fn:queue_bulk 124 \param udi: device for which que_bulk request is performed 125 \param buffer: data buffer, used in bulk i/o operation 126 \param len: length of data buffer 127 \param b_in: is "true" if input (device->host) data transfer, "false" otherwise 128 \return: status of operation. 129 130 performs queue_bulk USB request for corresponding pipe and handle timeout of this 131 operation. 132 */ 133 static status_t 134 queue_bulk(usb_device_info *udi, 135 void *buffer, 136 size_t len, 137 bool b_in) 138 { 139 status_t status = B_OK; 140 usb_pipe pipe = b_in ? udi->pipe_in : udi->pipe_out; 141 status = (*udi->usb_m->queue_bulk)(pipe, buffer, len, bulk_callback, udi); 142 if(status != B_OK){ 143 PTRACE_ALWAYS(udi, "queue_bulk:failed:%08x\n", status); 144 } else { 145 status = acquire_sem_etc(udi->trans_sem, 1, B_RELATIVE_TIMEOUT, udi->trans_timeout/*LOCK_TIMEOUT*/); 146 if(status != B_OK){ 147 PTRACE_ALWAYS(udi, "queue_bulk:acquire_sem_etc failed:%08x\n", status); 148 (*udi->usb_m->cancel_queued_transfers)(pipe); 149 } 150 } 151 return status; 152 } 153 /** 154 \fn:check_CSW 155 \param udi:corresponding device info 156 \param csw: CSW to be checked for validity and meaningfullness 157 \param transfer_len: data transferred during operation, which is checked for status 158 \return: "true" if CSW valid and meanigfull, "false" otherwise 159 160 checks CSW for validity and meaningfullness as required by USB mass strorge 161 BulkOnly specification ([2] 6.3) 162 */ 163 static bool 164 check_CSW(usb_device_info *udi, 165 usb_mass_CSW *csw, 166 int transfer_len) 167 { 168 bool is_valid = false; 169 do{ 170 /* check for CSW validity */ 171 if(udi->actual_len != CSW_LENGTH){ 172 PTRACE_ALWAYS(udi, "check_CSW:wrong length %d instead of %d\n", 173 udi->actual_len, CSW_LENGTH); 174 break;/* failed */ 175 } 176 if(csw->signature != CSW_SIGNATURE){ 177 PTRACE_ALWAYS(udi, "check_CSW:wrong signature %08x instead of %08x\n", 178 csw->signature, CSW_SIGNATURE); 179 break;/* failed */ 180 } 181 if(csw->tag != udi->tag - 1){ 182 PTRACE_ALWAYS(udi, "check_CSW:tag mismatch received:%d, awaited:%d\n", 183 csw->tag, udi->tag-1); 184 break;/* failed */ 185 } 186 /* check for CSW meaningfullness */ 187 if(CSW_STATUS_PHASE == csw->status){ 188 PTRACE_ALWAYS(udi, "check_CSW:not meaningfull: phase error\n"); 189 break;/* failed */ 190 } 191 if(transfer_len < csw->data_residue){ 192 PTRACE_ALWAYS(udi, "check_CSW:not meaningfull: " 193 "residue:%d is greater than transfer length:%d\n", 194 csw->data_residue, transfer_len); 195 break;/* failed */ 196 } 197 is_valid = true; 198 }while(false); 199 return is_valid; 200 } 201 /** 202 \fn:read_status 203 \param udi: corresponding device 204 \param csw: buffer for CSW data 205 \param transfer_len: data transferred during operation, which is checked for status 206 \return: success status code 207 208 reads CSW from device as proposed in ([2] 5.3.3; Figure 2.). 209 */ 210 static status_t 211 read_status(usb_device_info *udi, 212 usb_mass_CSW *csw, 213 int transfer_len) 214 { 215 status_t status = B_ERROR; 216 int try = 0; 217 do{ 218 status = queue_bulk(udi, csw, CSW_LENGTH, true); 219 if(0 == try){ 220 if(B_OK != status || B_OK != udi->status){ 221 status = (*udi->usb_m->clear_feature)(udi->pipe_in, USB_FEATURE_ENDPOINT_HALT); 222 if(status != 0){ 223 PTRACE_ALWAYS(udi, "read_status:failed 1st try, " 224 "status:%08x; usb_status:%08x\n", status, udi->status); 225 (*udi->protocol_m->reset)(udi); 226 break; 227 } 228 continue; /* go to second try*/ 229 } 230 /* CSW was readed without errors */ 231 } else { /* second try */ 232 if(B_OK != status || B_OK != udi->status){ 233 PTRACE_ALWAYS(udi, "read_status:failed 2nd try status:%08x; usb_status:%08x\n", 234 status, udi->status); 235 (*udi->protocol_m->reset)(udi); 236 status = (B_OK == status) ? udi->status : status; 237 break; 238 } 239 } 240 if(!check_CSW(udi, csw, transfer_len)){ 241 (*udi->protocol_m->reset)(udi); 242 status = B_ERROR; 243 break; 244 } 245 trace_CSW(udi, csw); 246 break; /* CSW was read successfully */ 247 }while(try++ < 2); 248 return status; 249 } 250 251 /*================= "standard" protocol procedures ==============================*/ 252 253 /** 254 \fn:bulk_only_initialize 255 \param udi: device on wich we should perform initialization 256 \return:error code if initialization failed or B_OK if it passed 257 258 initialize procedure for bulk only protocol devices. 259 */ 260 status_t 261 bulk_only_initialize(usb_device_info *udi) 262 { 263 status_t status = B_OK; 264 status = get_max_luns(udi); 265 return status; 266 } 267 /** 268 \fn:bulk_only_reset 269 \param udi: device on wich we should perform reset 270 \return:error code if reset failed or B_OK if it passed 271 272 reset procedure for bulk only protocol devices. Tries to send 273 BulkOnlyReset USB request and clear USB_FEATURE_ENDPOINT_HALT features on 274 input and output pipes. ([2] 3.1) 275 */ 276 status_t 277 bulk_only_reset(usb_device_info *udi) 278 { 279 status_t status = B_ERROR; 280 status = (*udi->usb_m->send_request)(udi->device, 281 USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT, 282 USB_REQ_MS_RESET, 0, 283 udi->interface, 0, 0, 0); 284 if(status != B_OK){ 285 PTRACE_ALWAYS(udi, "bulk_only_reset: reset request failed: %08x\n", status); 286 } 287 if(B_OK != (status = (*udi->usb_m->clear_feature)(udi->pipe_in, 288 USB_FEATURE_ENDPOINT_HALT))) 289 { 290 PTRACE_ALWAYS(udi, "bulk_only_reset: clear_feature on pipe_in failed: %08x\n", status); 291 } 292 if(B_OK != (status = (*udi->usb_m->clear_feature)(udi->pipe_out, 293 USB_FEATURE_ENDPOINT_HALT))) 294 { 295 PTRACE_ALWAYS(udi, "bulk_only_reset: clear_feature on pipe_out failed: %08x\n", status); 296 } 297 PTRACE(udi, "bulk_only_reset:%08x\n", status); 298 return status; 299 } 300 /** 301 \fn:bulk_only_transfer 302 \param udi: corresponding device 303 \param cmd: SCSI command to be performed on USB device 304 \param cmdlen: length of SCSI command 305 \param data_sg: io vectors array with data to transfer 306 \param sglist_count: count of entries in io vector array 307 \param transfer_len: overall length of data to be transferred 308 \param dir: direction of data transfer 309 \param ccbio: CCB_SCSIIO struct for original SCSI command 310 \param cb: callback to handle of final stage of command performing (autosense \ 311 request etc.) 312 313 transfer procedure for bulk-only protocol. Performs SCSI command on USB device 314 [2] 315 */ 316 void 317 bulk_only_transfer(usb_device_info *udi, 318 uint8 *cmd, 319 uint8 cmdlen, 320 //sg_buffer *sgb, 321 iovec *sg_data, 322 int32 sg_count, 323 int32 transfer_len, 324 EDirection dir, 325 CCB_SCSIIO *ccbio, 326 ud_transfer_callback cb) 327 { 328 status_t status = B_OK; 329 status_t command_status = B_OK; 330 int32 residue = transfer_len; 331 usb_mass_CSW csw = {0}; 332 /* initialize and fill in Command Block Wrapper */ 333 usb_mass_CBW cbw = { 334 .signature = CBW_SIGNATURE, 335 .tag = atomic_add(&udi->tag, 1), 336 .data_transfer_len = transfer_len, 337 .flags = (dir == eDirIn) ? CBW_FLAGS_IN : CBW_FLAGS_OUT, 338 .lun = ccbio->cam_ch.cam_target_lun & 0xf, 339 .cdb_len = cmdlen, 340 }; 341 memcpy(cbw.CDB, cmd, cbw.cdb_len); 342 do{ 343 trace_CBW(udi, &cbw); 344 /* send CBW to device */ 345 status = queue_bulk(udi, &cbw, CBW_LENGTH, false); 346 if(status != B_OK || udi->status != B_OK){ 347 PTRACE_ALWAYS(udi, "bulk_only_transfer: queue_bulk failed:" 348 "status:%08x usb status:%08x\n", status, udi->status); 349 (*udi->protocol_m->reset)(udi); 350 command_status = B_CMD_WIRE_FAILED; 351 break; 352 } 353 /* perform data transfer if required */ 354 if(transfer_len != 0x0){ 355 status = process_data_io(udi, sg_data, sg_count, dir); 356 if(status != B_OK && status != B_DEV_STALLED){ 357 command_status = B_CMD_WIRE_FAILED; 358 break; 359 } 360 } 361 /* get status of command */ 362 status = read_status(udi, &csw, transfer_len); 363 if(B_OK != status){ 364 command_status = B_CMD_WIRE_FAILED; 365 break; 366 } 367 residue = csw.data_residue; 368 if(csw.status == CSW_STATUS_FAILED){ 369 command_status = B_CMD_FAILED; 370 }else{ 371 command_status = B_OK; 372 } 373 }while(false); 374 /* finalize transfer */ 375 cb(udi, ccbio, residue, command_status); 376 } 377 378 protocol_module_info bulk_only_protocol_m = { 379 {0, 0, 0}, /* this is not a real kernel module - just interface */ 380 bulk_only_initialize, 381 bulk_only_reset, 382 bulk_only_transfer, 383 }; 384