📄 usb-storage.c
字号:
case US_PR_CBI: /* get from interrupt pipe */ /* add interrupt transfer, marked for removal */ us->ip_wanted = 1; /* go to sleep until we get this interrup */ /* FIXME: this should be changed to use a timeout */ sleep_on(&us->ip_waitq); if (us->ip_wanted) { US_DEBUGP("Did not get interrupt on CBI\n"); us->ip_wanted = 0; return USB_STOR_TRANSPORT_ERROR; } US_DEBUGP("Got interrupt data 0x%x\n", us->ip_data); /* UFI gives us ASC and ASCQ, like a request sense */ /* FIXME: is this right? do REQUEST_SENSE and INQUIRY need special * case handling? */ if (us->subclass == US_SC_UFI) { if (srb->cmnd[0] == REQUEST_SENSE || srb->cmnd[0] == INQUIRY) return USB_STOR_TRANSPORT_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; } } US_DEBUGP("pop_CB_status, reached end of function\n"); return USB_STOR_TRANSPORT_ERROR;}static int Bulk_reset(struct us_data *us){ int result; result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), US_BULK_RESET, USB_TYPE_CLASS | USB_RECIP_INTERFACE, US_BULK_RESET_HARD, us->ifnum, NULL, 0, HZ*5); if (result) US_DEBUGP("Bulk hard reset failed %d\n", result); usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); usb_clear_halt(us->pusb_dev, usb_sndbulkpipe(us->pusb_dev, us->ep_out)); /* long wait for reset */ schedule_timeout(HZ*6); return result;}/* * The bulk only protocol handler. * Uses the in and out endpoints to transfer commands and data */static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us){ struct bulk_cb_wrap bcb; struct bulk_cs_wrap bcs; int result; int pipe; int partial; /* set up the command wrapper */ bcb.Signature = US_BULK_CB_SIGN; bcb.DataTransferLength = us_transfer_length(srb); bcb.Flags = US_DIRECTION(srb->cmnd[0]) << 7; bcb.Tag = srb->serial_number; bcb.Lun = 0; bcb.Length = srb->cmd_len; /* construct the pipe handle */ pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); /* copy the command payload */ memset(bcb.CDB, 0, sizeof(bcb.CDB)); memcpy(bcb.CDB, srb->cmnd, bcb.Length); /* send it to out endpoint */ US_DEBUGP("Bulk command S 0x%x T 0x%x L %d F %d CL %d\n", bcb.Signature, bcb.Tag, bcb.DataTransferLength, bcb.Flags, bcb.Length); result = usb_bulk_msg(us->pusb_dev, pipe, &bcb, US_BULK_CB_WRAP_LEN, &partial, HZ*5); US_DEBUGP("Bulk command transfer result=%d\n", result); /* if we stall, we need to clear it before we go on */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); usb_clear_halt(us->pusb_dev, pipe); } /* if the command transfered well, then we go to the data stage */ /* FIXME: Regardless of the status of the data stage, we go on to the * status stage. Note that this implies that if a command is * partially successful, we rely on the device reporting an error * the CSW. The spec says that the device may just decide to short us. */ if (result == 0) { /* send/receive data payload, if there is any */ if (bcb.DataTransferLength) { result = us_transfer(srb, bcb.Flags); US_DEBUGP("Bulk data transfer result 0x%x\n", result);#if 0 if ((result < 0) && (result != USB_ST_DATAUNDERRUN) && (result != USB_ST_STALL)) { US_DEBUGP("Bulk data transfer result 0x%x\n", result); return DID_ABORT << 16; }#endif } } /* See flow chart on pg 15 of the Bulk Only Transport spec for * an explanation of how this code works. */ /* construct the pipe handle */ pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); /* get CSW for device status */ result = usb_bulk_msg(us->pusb_dev, pipe, &bcs, US_BULK_CS_WRAP_LEN, &partial, HZ*5); /* did the attempt to read the CSW fail? */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); usb_clear_halt(us->pusb_dev, pipe); /* get the status again */ result = usb_bulk_msg(us->pusb_dev, pipe, &bcs, US_BULK_CS_WRAP_LEN, &partial, HZ*5); /* if it fails again, we need a reset and return an error*/ if (result == -EPIPE) { Bulk_reset(us); return (DID_ABORT << 16); } } /* if we still have a failure at this point, we're in trouble */ if (result) { US_DEBUGP("Bulk status result = 0x%x\n", result); return DID_ABORT << 16; } /* check bulk status */ US_DEBUGP("Bulk status S 0x%x T 0x%x R %d V 0x%x\n", bcs.Signature, bcs.Tag, bcs.Residue, bcs.Status); if (bcs.Signature != US_BULK_CS_SIGN || bcs.Tag != bcb.Tag || bcs.Status > US_BULK_STAT_PHASE || partial != 13) { US_DEBUGP("Bulk logical error\n"); return DID_ABORT << 16; } /* based on the status code, we report good or bad */ switch (bcs.Status) { case US_BULK_STAT_OK: /* if there is residue, we really didn't finish the command */ if (bcs.Residue) return DID_ERROR << 16; else return DID_OK << 16; case US_BULK_STAT_FAIL: return DID_ERROR << 16; case US_BULK_STAT_PHASE: Bulk_reset(us); return DID_ERROR << 16; } return DID_OK << 16; /* check sense required */}/*********************************************************************** * Host functions ***********************************************************************//* detect adapter (always true ) */static int us_detect(struct SHT *sht){ /* FIXME - not nice at all, but how else ? */ struct us_data *us = (struct us_data *)sht->proc_dir; char name[32]; /* set up our name */ sprintf(name, "usbscsi%d", us->host_number); sht->name = sht->proc_name = kmalloc(strlen(name)+1, GFP_KERNEL); if (!sht->proc_name) return 0; strcpy(sht->proc_name, name); /* we start with no /proc directory entry */ sht->proc_dir = NULL; /* register the host */ us->host = scsi_register(sht, sizeof(us)); if (us->host) { us->host->hostdata[0] = (unsigned long)us; us->host_no = us->host->host_no; return 1; } /* odd... didn't register properly. Abort and free pointers */ kfree(sht->proc_name); sht->proc_name = NULL; sht->name = NULL; return 0;}/* release - must be here to stop scsi * from trying to release IRQ etc. * Kill off our data */static int us_release(struct Scsi_Host *psh){ struct us_data *us = (struct us_data *)psh->hostdata[0]; struct us_data *prev = (struct us_data *)&us_list; if (us->irq_handle) { usb_release_irq(us->pusb_dev, us->irq_handle, us->irqpipe); us->irq_handle = NULL; } if (us->pusb_dev) usb_deregister(&storage_driver); /* FIXME - leaves hanging host template copy */ /* (because scsi layer uses it after removal !!!) */ while (prev->next != us) prev = prev->next; prev->next = us->next; return 0;}/* run command */static int us_command( Scsi_Cmnd *srb ){ US_DEBUGP("Bad use of us_command\n"); return DID_BAD_TARGET << 16;}/* run command */static int us_queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *)){ struct us_data *us = (struct us_data *)srb->host->hostdata[0]; US_DEBUGP("Command wakeup\n"); if (us->srb) { /* busy */ } srb->host_scribble = (unsigned char *)us; us->srb = srb; srb->scsi_done = done; us->action = US_ACT_COMMAND; /* wake up the process task */ wake_up_interruptible(&us->waitq); return 0;}/* FIXME: This doesn't actually abort anything */static int us_abort( Scsi_Cmnd *srb ){ return 0;}static int us_bus_reset( Scsi_Cmnd *srb ){ // struct us_data *us = (struct us_data *)srb->host->hostdata[0]; US_DEBUGP("Bus reset requested\n"); // us->transport_reset(us); return SUCCESS;}/* FIXME: This doesn't actually reset anything */static int us_host_reset( Scsi_Cmnd *srb ){ return 0;}/*********************************************************************** * /proc/scsi/ functions ***********************************************************************//* we use this macro to help us write into the buffer */#undef SPRINTF#define SPRINTF(args...) do { if (pos < (buffer + length)) pos += sprintf (pos, ## args); } while (0)int usb_stor_proc_info (char *buffer, char **start, off_t offset, int length, int hostno, int inout){ struct us_data *us = us_list; char *pos = buffer; char *tmp_ptr; /* find our data from hostno */ while (us) { if (us->host_no == hostno) break; us = us->next; } /* if we couldn't find it, we return an error */ if (!us) return -ESRCH; /* if someone is sending us data, just throw it away */ if (inout) return length; /* print the controler name */ SPRINTF ("Host scsi%d: usb-storage\n", hostno); /* print product and vendor strings */ tmp_ptr = kmalloc(256, GFP_KERNEL); if (!us->pusb_dev || !tmp_ptr) { SPRINTF(" Vendor: Unknown Vendor\n"); SPRINTF(" Product: Unknown Product\n"); } else { SPRINTF(" Vendor: "); if (usb_string(us->pusb_dev, us->pusb_dev->descriptor.iManufacturer, tmp_ptr, 256) > 0) SPRINTF("%s\n", tmp_ptr); else SPRINTF("Unknown Vendor\n"); SPRINTF(" Product: "); if (usb_string(us->pusb_dev, us->pusb_dev->descriptor.iProduct, tmp_ptr, 256) > 0) SPRINTF("%s\n", tmp_ptr); else SPRINTF("Unknown Product\n"); kfree(tmp_ptr); } SPRINTF(" Protocol: "); switch (us->protocol) { case US_PR_CB: SPRINTF("Control/Bulk\n"); break; case US_PR_CBI: SPRINTF("Control/Bulk/Interrupt\n"); break; case US_PR_BULK: SPRINTF("Bulk only\n"); break; default: SPRINTF("Unknown Protocol\n"); break; } /* show the GUID of the device */ SPRINTF(" GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid)); /* * Calculate start of next buffer, and return value. */ *start = buffer + offset; if ((pos - buffer) < offset) return (0); else if ((pos - buffer - offset) < length) return (pos - buffer - offset); else return (length);}/* * this defines our 'host' */static Scsi_Host_Template my_host_template = { NULL, /* next */ NULL, /* module */ NULL, /* proc_dir */ usb_stor_proc_info, NULL, /* name - points to unique */ us_detect, us_release, NULL, /* info */ NULL, /* ioctl */ us_command, us_queuecommand, NULL, /* eh_strategy */ us_abort, us_bus_reset, us_bus_reset, us_host_reset, NULL, /* abort */ NULL, /* reset */ NULL, /* slave_attach */ NULL, /* bios_param */ NULL, /* select_queue_depths */ 1, /* can_queue */ -1, /* this_id */ SG_ALL, /* sg_tablesize */ 1, /* cmd_per_lun */ 0, /* present */ FALSE, /* unchecked_isa_dma */ FALSE, /* use_clustering */ TRUE, /* use_new_eh_code */ TRUE /* emulated */};static unsigned char sense_notready[] = { 0x70, /* current error */ 0x00, 0x02, /* not ready */ 0x00, 0x00, 0x0a, /* additional length */ 0x00, 0x00, 0x00, 0x00, 0x04, /* not ready */ 0x03, /* manual intervention */ 0x00, 0x00, 0x00, 0x00};static int usb_stor_control_thread(void * __us){ struct us_data *us = (struct us_data *)__us; int action; lock_kernel(); /* * This thread doesn't need any user-level access, * so get rid of all our resources.. */ daemonize(); sprintf(current->comm, "usbscsi%d", us->host_number); unlock_kernel(); up(us->notify);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -