📄 usb-storage.c
字号:
* REQUEST_SENSE -- either way, this belongs at a higher level */#if 0 /* For UFI, if this is the first time we've sent this TEST_UNIT_READY * command, we can try again */ if (!done_start && (us->subclass == US_SC_UFI) && (cmd[0] == TEST_UNIT_READY) && (result < 0)) { /* as per spec try a start command, wait and retry */ wait_ms(100); done_start++; memset(cmd, 0, sizeof(cmd)); cmd[0] = START_STOP; cmd[4] = 1; /* start */ result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, cmd, 12, HZ*5); US_DEBUGP("Next usb_control_msg returns %d\n", result); /* allow another retry */ retry++; continue; }#endif}static void transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us){ unsigned int savelen = us->srb->request_bufflen; unsigned int saveallocation = 0;#if 0 /* force attention on first command */ if (!us->attention_done) { if (us->srb->cmnd[0] == REQUEST_SENSE) { US_DEBUGP("forcing unit attention\n"); us->attention_done = 1; if (us->srb->result == USB_STOR_TRANSPORT_GOOD) { unsigned char *p = (unsigned char *)us->srb->request_buffer; if ((p[2] & 0x0f) != UNIT_ATTENTION) { p[2] = UNIT_ATTENTION; p[12] = 0x29; /* power on, reset or bus-reset */ p[13] = 0; } /* if ((p[2] & 0x0f) != UNIT_ATTENTION) */ } /* if (us->srb->result == USB_STORE_TRANSPORT_GOOD) */ } } /* if (!us->attention_done) */#endif /* If the command has a variable-length payload, then we do them * in two steps -- first we do the minimum, then we recalculate * then length, and re-issue the command * * we use savelen to remember how much buffer we really have * we use savealloction to remember how much was really requested */ /* FIXME: remove savelen based on mods to us_transfer_length() */ switch (us->srb->cmnd[0]) { case REQUEST_SENSE: if (us->srb->request_bufflen > 18) us->srb->request_bufflen = 18; else break; saveallocation = us->srb->cmnd[4]; us->srb->cmnd[4] = 18; break; case INQUIRY: if (us->srb->request_bufflen > 36) us->srb->request_bufflen = 36; else break; saveallocation = us->srb->cmnd[4]; us->srb->cmnd[4] = 36; break; case MODE_SENSE: if (us->srb->request_bufflen > 4) us->srb->request_bufflen = 4; else break; saveallocation = us->srb->cmnd[4]; us->srb->cmnd[4] = 4; break; case LOG_SENSE: case MODE_SENSE_10: if (us->srb->request_bufflen > 8) us->srb->request_bufflen = 8; else break; saveallocation = (us->srb->cmnd[7] << 8) | us->srb->cmnd[8]; us->srb->cmnd[7] = 0; us->srb->cmnd[8] = 8; break; default: break; } /* end switch on cmnd[0] */ /* This code supports devices which do not support {READ|WRITE}_6 * Apparently, neither Windows or MacOS will use these commands, * so some devices do not support them */ if (us->flags & US_FL_MODE_XLATE) { /* translate READ_6 to READ_10 */ if (us->srb->cmnd[0] == 0x08) { /* get the control */ us->srb->cmnd[9] = us->srb->cmnd[5]; /* get the length */ us->srb->cmnd[8] = us->srb->cmnd[6]; us->srb->cmnd[7] = 0; /* set the reserved area to 0 */ us->srb->cmnd[6] = 0; /* get LBA */ us->srb->cmnd[5] = us->srb->cmnd[3]; us->srb->cmnd[4] = us->srb->cmnd[2]; us->srb->cmnd[3] = 0; us->srb->cmnd[2] = 0; /* LUN and other info in cmnd[1] can stay */ /* fix command code */ us->srb->cmnd[0] = 0x28; US_DEBUGP("Changing READ_6 to READ_10\n"); US_DEBUG(us_show_command(us->srb)); } /* translate WRITE_6 to WRITE_10 */ if (us->srb->cmnd[0] == 0x0A) { /* get the control */ us->srb->cmnd[9] = us->srb->cmnd[5]; /* get the length */ us->srb->cmnd[8] = us->srb->cmnd[4]; us->srb->cmnd[7] = 0; /* set the reserved area to 0 */ us->srb->cmnd[6] = 0; /* get LBA */ us->srb->cmnd[5] = us->srb->cmnd[3]; us->srb->cmnd[4] = us->srb->cmnd[2]; us->srb->cmnd[3] = 0; us->srb->cmnd[2] = 0; /* LUN and other info in cmnd[1] can stay */ /* fix command code */ us->srb->cmnd[0] = 0x2A; US_DEBUGP("Changing WRITE_6 to WRITE_10\n"); US_DEBUG(us_show_command(us->srb)); } } /* end if (us->flags & US_FL_MODE_XLATE) */ /* send the command to the transport layer */ us->srb->result = us->transport(us->srb, us); /* if we have an error, we're going to do a REQUEST_SENSE * automatically */ /* FIXME: we should only do this for device errors, not * system errors */ if (us->srb->result) { int temp_result; int count; void* old_request_buffer; US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n"); /* set the result so the higher layers expect this data */ us->srb->result = CHECK_CONDITION; us->srb->cmnd[0] = REQUEST_SENSE; us->srb->cmnd[1] = 0; us->srb->cmnd[2] = 0; us->srb->cmnd[3] = 0; us->srb->cmnd[4] = 18; us->srb->cmnd[5] = 0; /* set the buffer length for transfer */ old_request_buffer = us->srb->request_buffer; us->srb->request_bufflen = 18; us->srb->request_buffer = kmalloc(18, GFP_KERNEL); /* FIXME: what if this command fails? */ temp_result = us->transport(us->srb, us); US_DEBUGP("-- Result from auto-sense is %d\n", temp_result); /* copy the data from the request buffer to the sense buffer */ for(count = 0; count < 18; count++) us->srb->sense_buffer[count] = ((unsigned char *)(us->srb->request_buffer))[count]; US_DEBUGP("-- sense key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n", us->srb->sense_buffer[2] & 0xf, us->srb->sense_buffer[12], us->srb->sense_buffer[13]); /* we're done here */ kfree(us->srb->request_buffer); us->srb->request_buffer = old_request_buffer; return; } if (savelen != us->srb->request_bufflen) { unsigned char *p = (unsigned char *)us->srb->request_buffer; unsigned int length = 0; /* set correct length and retry */ switch (us->srb->cmnd[0]) { /* FIXME: we should try to get all the sense data */ case REQUEST_SENSE: /* simply return 18 bytes */ p[7] = 10; length = us->srb->request_bufflen; break; case INQUIRY: length = p[4] + 5 > savelen ? savelen : p[4] + 5; us->srb->cmnd[4] = length; break; case MODE_SENSE: US_DEBUGP("MODE_SENSE Mode data length is %d\n", p[0]); length = p[0] + 1 > savelen ? savelen : p[0] + 1; us->srb->cmnd[4] = length; break; case LOG_SENSE: length = ((p[2] << 8) + p[3]) + 4 > savelen ? savelen : ((p[2] << 8) + p[3]) + 4; us->srb->cmnd[7] = length >> 8; us->srb->cmnd[8] = length; break; case MODE_SENSE_10: US_DEBUGP("MODE_SENSE_10 Mode data length is %d\n", (p[0] << 8) + p[1]); length = ((p[0] << 8) + p[1]) + 6 > savelen ? savelen : ((p[0] << 8) + p[1]) + 6; us->srb->cmnd[7] = length >> 8; us->srb->cmnd[8] = length; break; } /* end switch on cmnd[0] */ US_DEBUGP("Old/New length = %d/%d\n", savelen, length); /* issue the new command */ /* FIXME: this assumes that the second attempt is * always successful */ if (us->srb->request_bufflen != length) { US_DEBUGP("redoing cmd with len=%d\n", length); us->srb->request_bufflen = length; us->srb->result = us->transport(us->srb, us); } /* reset back to original values */ us->srb->request_bufflen = savelen; /* fix data as necessary */ switch (us->srb->cmnd[0]) { case INQUIRY: if ((((unsigned char*)us->srb->request_buffer)[2] & 0x7) == 0) { US_DEBUGP("Fixing INQUIRY data, setting SCSI rev to 2\n"); ((unsigned char*)us->srb->request_buffer)[2] |= 2; } /* FALL THROUGH */ case REQUEST_SENSE: case MODE_SENSE: if (us->srb->use_sg == 0 && length > 0) { int i; printk(KERN_DEBUG "Data is"); for (i = 0; i < 32 && i < length; ++i) printk(" %.2x", ((unsigned char *)us->srb->request_buffer)[i]); if (i < length) printk(" ..."); printk("\n"); } /* FIXME: is this really necessary? */ us->srb->cmnd[4] = saveallocation; break; case LOG_SENSE: case MODE_SENSE_10: /* FIXME: is this really necessary? */ us->srb->cmnd[7] = saveallocation >> 8; us->srb->cmnd[8] = saveallocation; break; } /* end switch on cmnd[0] */ } /* if good command */}/*********************************************************************** * Transport routines ***********************************************************************/static int CBI_irq(int state, void *buffer, int len, void *dev_id){ struct us_data *us = (struct us_data *)dev_id; US_DEBUGP("USB IRQ recieved for device on host %d\n", us->host_no); /* save the data for interpretation later */ if (state != USB_ST_REMOVED) { us->ip_data = le16_to_cpup((__u16 *)buffer); US_DEBUGP("Interrupt Status 0x%x\n", us->ip_data); } /* was this a wanted interrupt? */ if (us->ip_wanted) { us->ip_wanted = 0; wake_up(&us->ip_waitq); } else { US_DEBUGP("ERROR: Unwanted interrupt received!\n"); } /* This return code is truly meaningless -- and I mean truly. It gets * ignored by other layers. It used to indicate if we wanted to get * another interrupt or disable the interrupt callback */ return 0;}/* FIXME: this reset function doesn't really reset the port, and it * should. Actually it should probably do what it's doing here, and * reset the port physically */static int CB_reset(struct us_data *us){ unsigned char cmd[12]; int result; US_DEBUGP("CB_reset\n"); memset(cmd, 0xFF, sizeof(cmd)); cmd[0] = SEND_DIAGNOSTIC; cmd[1] = 4; result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, cmd, sizeof(cmd), HZ*5); /* long wait for reset */ schedule_timeout(HZ*6); US_DEBUGP("CB_reset: clearing endpoint halt\n"); usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_out)); US_DEBUGP("CB_reset done\n"); return 0;}static int pop_CB_status(Scsi_Cmnd *srb);/* FIXME: we also need a CBI_command which sets up the completion * interrupt, and waits for it */static int CB_transport(Scsi_Cmnd *srb, struct us_data *us){ int result; US_DEBUGP("CBI gets a command:\n"); US_DEBUG(us_show_command(srb)); /* FIXME: we aren't setting the ip_wanted indicator early enough, which * causes some commands to never complete. This hangs the driver. */ /* let's send the command via the control pipe */ result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, srb->cmnd, srb->cmd_len, HZ*5); /* check the return code for the command */ if (result < 0) { US_DEBUGP("Call to usb_control_msg() returned %d\n", result); /* a stall is a fatal condition from the device */ if (result == -EPIPE) { US_DEBUGP("-- Stall on control pipe detected. Clearing\n"); US_DEBUGP("-- Return from usb_clear_halt() is %d\n", usb_clear_halt(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0))); return USB_STOR_TRANSPORT_ERROR; } /* FIXME: we need to handle NAKs here */ return USB_STOR_TRANSPORT_ERROR; } /* transfer the data payload for this command, if one exists*/ if (us_transfer_length(srb)) { result = us_transfer(srb, US_DIRECTION(srb->cmnd[0])); US_DEBUGP("CBI attempted to transfer data, result is 0x%x\n", result); /* FIXME: what do the return codes from us_transfer mean? */ if ((result < 0) && (result != USB_ST_DATAUNDERRUN) && (result != USB_ST_STALL)) { return DID_ERROR << 16; } } /* if (us_transfer_length(srb)) */ /* get status and return it */ return pop_CB_status(srb);}/* * Control/Bulk status handler */static int pop_CB_status(Scsi_Cmnd *srb){ struct us_data *us = (struct us_data *)srb->host_scribble; int result = 0; __u8 status[2]; int retry = 5; US_DEBUGP("pop_CB_status, proto=0x%x\n", us->protocol); switch (us->protocol) { case US_PR_CB: /* get from control */ while (retry--) { result = usb_control_msg(us->pusb_dev, usb_rcvctrlpipe(us->pusb_dev,0), USB_REQ_GET_STATUS, USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE, 0, us->ifnum, status, sizeof(status), HZ*5); if (result != USB_ST_TIMEOUT) break; } if (result) { US_DEBUGP("Bad AP status request %d\n", result); return DID_ABORT << 16; } US_DEBUGP("Got AP status 0x%x 0x%x\n", status[0], status[1]); if (srb->cmnd[0] != REQUEST_SENSE && srb->cmnd[0] != INQUIRY && ( (status[0] & ~3) || status[1])) return (DID_OK << 16) | 2; else return USB_STOR_TRANSPORT_GOOD; break; /* FIXME: this should be in a separate function */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -