📄 usb_storage.c
字号:
{ unsigned char cmd[12]; int result; USB_STOR_PRINTF("CB_reset\n"); memset(cmd, 0xFF, sizeof(cmd)); cmd[0] = SCSI_SEND_DIAG; 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), USB_CNTL_TIMEOUT*5); /* long wait for reset */ wait_ms(1500); USB_STOR_PRINTF("CB_reset result %d: status %X clearing endpoint halt\n",result,us->pusb_dev->status); 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)); USB_STOR_PRINTF("CB_reset done\n"); return 0;}/* * Set up the command for a BBB device. Note that the actual SCSI * command is copied into cbw.CBWCDB. */int usb_stor_BBB_comdat(ccb *srb, struct us_data *us){ int result; int actlen; int dir_in; unsigned int pipe; umass_bbb_cbw_t cbw; dir_in = US_DIRECTION(srb->cmd[0]);#ifdef BBB_COMDAT_TRACE printf("dir %d lun %d cmdlen %d cmd %p datalen %d pdata %p\n", dir_in, srb->lun, srb->cmdlen, srb->cmd, srb->datalen, srb->pdata); if (srb->cmdlen) { for(result = 0;result < srb->cmdlen;result++) printf("cmd[%d] %#x ", result, srb->cmd[result]); printf("\n"); }#endif /* sanity checks */ if (!(srb->cmdlen <= CBWCDBLENGTH)) { USB_STOR_PRINTF("usb_stor_BBB_comdat:cmdlen too large\n"); return -1; } /* always OUT to the ep */ pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); cbw.dCBWSignature = swap_32(CBWSIGNATURE); cbw.dCBWTag = swap_32(CBWTag++); cbw.dCBWDataTransferLength = swap_32(srb->datalen); cbw.bCBWFlags = (dir_in? CBWFLAGS_IN : CBWFLAGS_OUT); cbw.bCBWLUN = srb->lun; cbw.bCDBLength = srb->cmdlen; /* copy the command data into the CBW command data buffer */ /* DST SRC LEN!!! */ memcpy(cbw.CBWCDB, srb->cmd, srb->cmdlen); result = usb_bulk_msg(us->pusb_dev, pipe, &cbw, UMASS_BBB_CBW_SIZE, &actlen, USB_CNTL_TIMEOUT*5); if (result < 0) USB_STOR_PRINTF("usb_stor_BBB_comdat:usb_bulk_msg error\n"); return result;}/* FIXME: we also need a CBI_command which sets up the completion * interrupt, and waits for it */int usb_stor_CB_comdat(ccb *srb, struct us_data *us){ int result; int dir_in,retry; unsigned int pipe; unsigned long status; retry=5; dir_in=US_DIRECTION(srb->cmd[0]); if(dir_in) pipe=usb_rcvbulkpipe(us->pusb_dev, us->ep_in); else pipe=usb_sndbulkpipe(us->pusb_dev, us->ep_out); while(retry--) { USB_STOR_PRINTF("CBI gets a command: Try %d\n",5-retry);#ifdef USB_STOR_DEBUG usb_show_srb(srb);#endif /* 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->cmd, srb->cmdlen, USB_CNTL_TIMEOUT*5); USB_STOR_PRINTF("CB_transport: control msg returned %d, status %X\n",result,us->pusb_dev->status); /* check the return code for the command */ if (result < 0) { if(us->pusb_dev->status & USB_ST_STALLED) { status=us->pusb_dev->status; USB_STOR_PRINTF(" stall during command found, clear pipe\n"); usb_clear_halt(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0)); us->pusb_dev->status=status; } USB_STOR_PRINTF(" error during command %02X Stat = %X\n",srb->cmd[0],us->pusb_dev->status); return result; } /* transfer the data payload for this command, if one exists*/ USB_STOR_PRINTF("CB_transport: control msg returned %d, direction is %s to go 0x%lx\n",result,dir_in ? "IN" : "OUT",srb->datalen); if (srb->datalen) { result = us_one_transfer(us, pipe, srb->pdata,srb->datalen); USB_STOR_PRINTF("CBI attempted to transfer data, result is %d status %lX, len %d\n", result,us->pusb_dev->status,us->pusb_dev->act_len); if(!(us->pusb_dev->status & USB_ST_NAK_REC)) break; } /* if (srb->datalen) */ else break; } /* return result */ return result;}int usb_stor_CBI_get_status (ccb * srb, struct us_data *us){ int timeout; us->ip_wanted = 1; submit_int_msg (us->pusb_dev, us->irqpipe, (void *) &us->ip_data, us->irqmaxp, us->irqinterval); timeout = 1000; while (timeout--) { if ((volatile int *) us->ip_wanted == 0) break; wait_ms (10); } if (us->ip_wanted) { printf (" Did not get interrupt on CBI\n"); us->ip_wanted = 0; return USB_STOR_TRANSPORT_ERROR; } USB_STOR_PRINTF ("Got interrupt data 0x%x, transfered %d status 0x%lX\n", us->ip_data, us->pusb_dev->irq_act_len, us->pusb_dev->irq_status); /* UFI gives us ASC and ASCQ, like a request sense */ if (us->subclass == US_SC_UFI) { if (srb->cmd[0] == SCSI_REQ_SENSE || srb->cmd[0] == SCSI_INQUIRY) return USB_STOR_TRANSPORT_GOOD; /* Good */ else if (us->ip_data) return USB_STOR_TRANSPORT_FAILED; else return USB_STOR_TRANSPORT_GOOD; } /* otherwise, we interpret the data normally */ switch (us->ip_data) { case 0x0001: return USB_STOR_TRANSPORT_GOOD; case 0x0002: return USB_STOR_TRANSPORT_FAILED; default: return USB_STOR_TRANSPORT_ERROR; } /* switch */ return USB_STOR_TRANSPORT_ERROR;}#define USB_TRANSPORT_UNKNOWN_RETRY 5#define USB_TRANSPORT_NOT_READY_RETRY 10/* clear a stall on an endpoint - special for BBB devices */int usb_stor_BBB_clear_endpt_stall(struct us_data *us, __u8 endpt){ int result; /* ENDPOINT_HALT = 0, so set value to 0 */ result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, endpt, 0, 0, USB_CNTL_TIMEOUT*5); return result;}int usb_stor_BBB_transport(ccb *srb, struct us_data *us){ int result, retry; int dir_in; int actlen, data_actlen; unsigned int pipe, pipein, pipeout; umass_bbb_csw_t csw;#ifdef BBB_XPORT_TRACE unsigned char *ptr; int index;#endif dir_in = US_DIRECTION(srb->cmd[0]); /* COMMAND phase */ USB_STOR_PRINTF("COMMAND phase\n"); result = usb_stor_BBB_comdat(srb, us); if (result < 0) { USB_STOR_PRINTF("failed to send CBW status %ld\n", us->pusb_dev->status); usb_stor_BBB_reset(us); return USB_STOR_TRANSPORT_FAILED; } wait_ms(5); pipein = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); pipeout = usb_sndbulkpipe(us->pusb_dev, us->ep_out); /* DATA phase + error handling */ data_actlen = 0; /* no data, go immediately to the STATUS phase */ if (srb->datalen == 0) goto st; USB_STOR_PRINTF("DATA phase\n"); if (dir_in) pipe = pipein; else pipe = pipeout; result = usb_bulk_msg(us->pusb_dev, pipe, srb->pdata, srb->datalen, &data_actlen, USB_CNTL_TIMEOUT*5); /* special handling of STALL in DATA phase */ if((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) { USB_STOR_PRINTF("DATA:stall\n"); /* clear the STALL on the endpoint */ result = usb_stor_BBB_clear_endpt_stall(us, dir_in? us->ep_in : us->ep_out); if (result >= 0) /* continue on to STATUS phase */ goto st; } if (result < 0) { USB_STOR_PRINTF("usb_bulk_msg error status %ld\n", us->pusb_dev->status); usb_stor_BBB_reset(us); return USB_STOR_TRANSPORT_FAILED; }#ifdef BBB_XPORT_TRACE for (index = 0; index < data_actlen; index++) printf("pdata[%d] %#x ", index, srb->pdata[index]); printf("\n");#endif /* STATUS phase + error handling */ st: retry = 0; again: USB_STOR_PRINTF("STATUS phase\n"); result = usb_bulk_msg(us->pusb_dev, pipein, &csw, UMASS_BBB_CSW_SIZE, &actlen, USB_CNTL_TIMEOUT*5); /* special handling of STALL in STATUS phase */ if((result < 0) && (retry < 1) && (us->pusb_dev->status & USB_ST_STALLED)) { USB_STOR_PRINTF("STATUS:stall\n"); /* clear the STALL on the endpoint */ result = usb_stor_BBB_clear_endpt_stall(us, us->ep_in); if (result >= 0 && (retry++ < 1)) /* do a retry */ goto again; } if (result < 0) { USB_STOR_PRINTF("usb_bulk_msg error status %ld\n", us->pusb_dev->status); usb_stor_BBB_reset(us); return USB_STOR_TRANSPORT_FAILED; }#ifdef BBB_XPORT_TRACE ptr = (unsigned char *)&csw; for (index = 0; index < UMASS_BBB_CSW_SIZE; index++) printf("ptr[%d] %#x ", index, ptr[index]); printf("\n");#endif /* misuse pipe to get the residue */ pipe = swap_32(csw.dCSWDataResidue); if (pipe == 0 && srb->datalen != 0 && srb->datalen - data_actlen != 0) pipe = srb->datalen - data_actlen; if (CSWSIGNATURE != swap_32(csw.dCSWSignature)) { USB_STOR_PRINTF("!CSWSIGNATURE\n"); usb_stor_BBB_reset(us); return USB_STOR_TRANSPORT_FAILED; } else if ((CBWTag - 1) != swap_32(csw.dCSWTag)) { USB_STOR_PRINTF("!Tag\n"); usb_stor_BBB_reset(us); return USB_STOR_TRANSPORT_FAILED; } else if (csw.bCSWStatus > CSWSTATUS_PHASE) { USB_STOR_PRINTF(">PHASE\n"); usb_stor_BBB_reset(us); return USB_STOR_TRANSPORT_FAILED; } else if (csw.bCSWStatus == CSWSTATUS_PHASE) { USB_STOR_PRINTF("=PHASE\n"); usb_stor_BBB_reset(us); return USB_STOR_TRANSPORT_FAILED; } else if (data_actlen > srb->datalen) { USB_STOR_PRINTF("transferred %dB instead of %dB\n", data_actlen, srb->datalen); return USB_STOR_TRANSPORT_FAILED; } else if (csw.bCSWStatus == CSWSTATUS_FAILED) { USB_STOR_PRINTF("FAILED\n"); return USB_STOR_TRANSPORT_FAILED; } return result;}int usb_stor_CB_transport(ccb *srb, struct us_data *us){ int result,status; ccb *psrb; ccb reqsrb; int retry,notready; psrb=&reqsrb; status=USB_STOR_TRANSPORT_GOOD; retry=0; notready=0; /* issue the command */do_retry: result=usb_stor_CB_comdat(srb,us); USB_STOR_PRINTF("command / Data returned %d, status %X\n",result,us->pusb_dev->status); /* if this is an CBI Protocol, get IRQ */ if(us->protocol==US_PR_CBI) { status=usb_stor_CBI_get_status(srb,us); /* if the status is error, report it */ if(status==USB_STOR_TRANSPORT_ERROR) { USB_STOR_PRINTF(" USB CBI Command Error\n"); return status; } srb->sense_buf[12]=(unsigned char)(us->ip_data>>8); srb->sense_buf[13]=(unsigned char)(us->ip_data&0xff); if(!us->ip_data) { /* if the status is good, report it */ if(status==USB_STOR_TRANSPORT_GOOD) { USB_STOR_PRINTF(" USB CBI Command Good\n"); return status; } } } /* do we have to issue an auto request? */ /* HERE we have to check the result */ if((result<0) && !(us->pusb_dev->status & USB_ST_STALLED)) { USB_STOR_PRINTF("ERROR %X\n",us->pusb_dev->status); us->transport_reset(us); return USB_STOR_TRANSPORT_ERROR; } if((us->protocol==US_PR_CBI) && ((srb->cmd[0]==SCSI_REQ_SENSE) || (srb->cmd[0]==SCSI_INQUIRY))) { /* do not issue an autorequest after request sense */ USB_STOR_PRINTF("No auto request and good\n"); return USB_STOR_TRANSPORT_GOOD; } /* issue an request_sense */ memset(&psrb->cmd[0],0,12); psrb->cmd[0]=SCSI_REQ_SENSE; psrb->cmd[1]=srb->lun<<5; psrb->cmd[4]=18; psrb->datalen=18; psrb->pdata=&srb->sense_buf[0]; psrb->cmdlen=12; /* issue the command */ result=usb_stor_CB_comdat(psrb,us); USB_STOR_PRINTF("auto request returned %d\n",result); /* if this is an CBI Protocol, get IRQ */ if(us->protocol==US_PR_CBI) { status=usb_stor_CBI_get_status(psrb,us); } if((result<0)&&!(us->pusb_dev->status & USB_ST_STALLED)) { USB_STOR_PRINTF(" AUTO REQUEST ERROR %d\n",us->pusb_dev->status); return USB_STOR_TRANSPORT_ERROR; } USB_STOR_PRINTF("autorequest returned 0x%02X 0x%02X 0x%02X 0x%02X\n",srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]); /* Check the auto request result */ if((srb->sense_buf[2]==0) && (srb->sense_buf[12]==0) && (srb->sense_buf[13]==0)) /* ok, no sense */ return USB_STOR_TRANSPORT_GOOD; /* Check the auto request result */ switch(srb->sense_buf[2]) { case 0x01: /* Recovered Error */ return USB_STOR_TRANSPORT_GOOD; break; case 0x02: /* Not Ready */ if(notready++ > USB_TRANSPORT_NOT_READY_RETRY) { printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X 0x%02X (NOT READY)\n", srb->cmd[0],srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]); return USB_STOR_TRANSPORT_FAILED; } else { wait_ms(100); goto do_retry; } break; default: if(retry++ > USB_TRANSPORT_UNKNOWN_RETRY) { printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X 0x%02X\n", srb->cmd[0],srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]); return USB_STOR_TRANSPORT_FAILED; } else { goto do_retry; } break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -