diff options
Diffstat (limited to 'drivers/usb/storage')
-rw-r--r-- | drivers/usb/storage/debug.c | 17 | ||||
-rw-r--r-- | drivers/usb/storage/debug.h | 10 | ||||
-rw-r--r-- | drivers/usb/storage/initializers.c | 5 | ||||
-rw-r--r-- | drivers/usb/storage/realtek_cr.c | 2 | ||||
-rw-r--r-- | drivers/usb/storage/transport.c | 43 | ||||
-rw-r--r-- | drivers/usb/storage/uas.c | 69 | ||||
-rw-r--r-- | drivers/usb/storage/unusual_uas.h | 35 | ||||
-rw-r--r-- | drivers/usb/storage/usb.c | 36 |
8 files changed, 142 insertions, 75 deletions
diff --git a/drivers/usb/storage/debug.c b/drivers/usb/storage/debug.c index e08f64780e30..57bf3ad41fb6 100644 --- a/drivers/usb/storage/debug.c +++ b/drivers/usb/storage/debug.c @@ -164,10 +164,10 @@ void usb_stor_show_sense(const struct us_data *us, unsigned char asc, unsigned char ascq) { - const char *what, *keystr; + const char *what, *keystr, *fmt; keystr = scsi_sense_key_string(key); - what = scsi_extd_sense_format(asc, ascq); + what = scsi_extd_sense_format(asc, ascq, &fmt); if (keystr == NULL) keystr = "(Unknown Key)"; @@ -175,21 +175,20 @@ void usb_stor_show_sense(const struct us_data *us, what = "(unknown ASC/ASCQ)"; usb_stor_dbg(us, "%s: ", keystr); - US_DEBUGPX(what, ascq); - US_DEBUGPX("\n"); + if (fmt) + US_DEBUGPX("%s (%s%x)\n", what, fmt, ascq); + else + US_DEBUGPX("%s\n", what); } -int usb_stor_dbg(const struct us_data *us, const char *fmt, ...) +void usb_stor_dbg(const struct us_data *us, const char *fmt, ...) { va_list args; - int r; va_start(args, fmt); - r = dev_vprintk_emit(7, &us->pusb_dev->dev, fmt, args); + dev_vprintk_emit(LOGLEVEL_DEBUG, &us->pusb_dev->dev, fmt, args); va_end(args); - - return r; } EXPORT_SYMBOL_GPL(usb_stor_dbg); diff --git a/drivers/usb/storage/debug.h b/drivers/usb/storage/debug.h index b1273f03e223..f52520306e1a 100644 --- a/drivers/usb/storage/debug.h +++ b/drivers/usb/storage/debug.h @@ -50,15 +50,17 @@ void usb_stor_show_command(const struct us_data *us, struct scsi_cmnd *srb); void usb_stor_show_sense(const struct us_data *us, unsigned char key, unsigned char asc, unsigned char ascq); -__printf(2, 3) int usb_stor_dbg(const struct us_data *us, - const char *fmt, ...); +__printf(2, 3) void usb_stor_dbg(const struct us_data *us, + const char *fmt, ...); #define US_DEBUGPX(fmt, ...) printk(fmt, ##__VA_ARGS__) #define US_DEBUG(x) x #else __printf(2, 3) -static inline int _usb_stor_dbg(const struct us_data *us, - const char *fmt, ...) {return 1;} +static inline void _usb_stor_dbg(const struct us_data *us, + const char *fmt, ...) +{ +} #define usb_stor_dbg(us, fmt, ...) \ do { if (0) _usb_stor_dbg(us, fmt, ##__VA_ARGS__); } while (0) #define US_DEBUGPX(fmt, ...) \ diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c index 4bc2fc98636e..31fa2e92065b 100644 --- a/drivers/usb/storage/initializers.c +++ b/drivers/usb/storage/initializers.c @@ -49,10 +49,9 @@ int usb_stor_euscsi_init(struct us_data *us) int result; usb_stor_dbg(us, "Attempting to init eUSCSI bridge...\n"); - us->iobuf[0] = 0x1; result = usb_stor_control_msg(us, us->send_ctrl_pipe, 0x0C, USB_RECIP_INTERFACE | USB_TYPE_VENDOR, - 0x01, 0x0, us->iobuf, 0x1, USB_CTRL_SET_TIMEOUT); + 0x01, 0x0, NULL, 0x0, 5 * HZ); usb_stor_dbg(us, "-- result is %d\n", result); return 0; @@ -100,7 +99,7 @@ int usb_stor_huawei_e220_init(struct us_data *us) result = usb_stor_control_msg(us, us->send_ctrl_pipe, USB_REQ_SET_FEATURE, USB_TYPE_STANDARD | USB_RECIP_DEVICE, - 0x01, 0x0, NULL, 0x0, 1000); + 0x01, 0x0, NULL, 0x0, 1 * HZ); usb_stor_dbg(us, "Huawei mode set result is %d\n", result); return 0; } diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c index 8591d89a38e6..27e4a580d2ed 100644 --- a/drivers/usb/storage/realtek_cr.c +++ b/drivers/usb/storage/realtek_cr.c @@ -626,6 +626,7 @@ static int config_autodelink_after_power_on(struct us_data *us) return 0; } +#ifdef CONFIG_PM static int config_autodelink_before_power_down(struct us_data *us) { struct rts51x_chip *chip = (struct rts51x_chip *)(us->extra); @@ -716,6 +717,7 @@ static void fw5895_init(struct us_data *us) } } } +#endif #ifdef CONFIG_REALTEK_AUTOPM static void fw5895_set_mmc_wp(struct us_data *us) diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 22c7d4360fa2..540add24a12f 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -1035,9 +1035,20 @@ int usb_stor_Bulk_max_lun(struct us_data *us) usb_stor_dbg(us, "GetMaxLUN command result is %d, data is %d\n", result, us->iobuf[0]); - /* if we have a successful request, return the result */ - if (result > 0) - return us->iobuf[0]; + /* + * If we have a successful request, return the result if valid. The + * CBW LUN field is 4 bits wide, so the value reported by the device + * should fit into that. + */ + if (result > 0) { + if (us->iobuf[0] < 16) { + return us->iobuf[0]; + } else { + dev_info(&us->pusb_intf->dev, + "Max LUN %d is not valid, using 0 instead", + us->iobuf[0]); + } + } /* * Some devices don't like GetMaxLUN. They may STALL the control @@ -1118,6 +1129,31 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) */ if (result == USB_STOR_XFER_LONG) fake_sense = 1; + + /* + * Sometimes a device will mistakenly skip the data phase + * and go directly to the status phase without sending a + * zero-length packet. If we get a 13-byte response here, + * check whether it really is a CSW. + */ + if (result == USB_STOR_XFER_SHORT && + srb->sc_data_direction == DMA_FROM_DEVICE && + transfer_length - scsi_get_resid(srb) == + US_BULK_CS_WRAP_LEN) { + struct scatterlist *sg = NULL; + unsigned int offset = 0; + + if (usb_stor_access_xfer_buf((unsigned char *) bcs, + US_BULK_CS_WRAP_LEN, srb, &sg, + &offset, FROM_XFER_BUF) == + US_BULK_CS_WRAP_LEN && + bcs->Signature == + cpu_to_le32(US_BULK_CS_SIGN)) { + usb_stor_dbg(us, "Device skipped data phase\n"); + scsi_set_resid(srb, transfer_length); + goto skipped_data_phase; + } + } } /* See flow chart on pg 15 of the Bulk Only Transport spec for @@ -1153,6 +1189,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; + skipped_data_phase: /* check bulk status */ residue = le32_to_cpu(bcs->Residue); usb_stor_dbg(us, "Bulk Status S 0x%x T 0x%x R %u Stat 0x%x\n", diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index 89b24349269e..6cdabdc119a7 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -66,7 +66,7 @@ enum { /* Overrides scsi_pointer */ struct uas_cmd_info { unsigned int state; - unsigned int stream; + unsigned int uas_tag; struct urb *cmd_urb; struct urb *data_in_urb; struct urb *data_out_urb; @@ -173,30 +173,15 @@ static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd) cmnd->result = sense_iu->status; } -/* - * scsi-tags go from 0 - (nr_tags - 1), uas tags need to match stream-ids, - * which go from 1 - nr_streams. And we use 1 for untagged commands. - */ -static int uas_get_tag(struct scsi_cmnd *cmnd) -{ - int tag; - - if (blk_rq_tagged(cmnd->request)) - tag = cmnd->request->tag + 2; - else - tag = 1; - - return tag; -} - static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *prefix, int status) { struct uas_cmd_info *ci = (void *)&cmnd->SCp; + struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; scmd_printk(KERN_INFO, cmnd, - "%s %d tag %d inflight:%s%s%s%s%s%s%s%s%s%s%s%s ", - prefix, status, uas_get_tag(cmnd), + "%s %d uas-tag %d inflight:%s%s%s%s%s%s%s%s%s%s%s%s ", + prefix, status, cmdinfo->uas_tag, (ci->state & SUBMIT_STATUS_URB) ? " s-st" : "", (ci->state & ALLOC_DATA_IN_URB) ? " a-in" : "", (ci->state & SUBMIT_DATA_IN_URB) ? " s-in" : "", @@ -242,7 +227,7 @@ static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller) DATA_OUT_URB_INFLIGHT | COMMAND_ABORTED)) return -EBUSY; - devinfo->cmnd[uas_get_tag(cmnd) - 1] = NULL; + devinfo->cmnd[cmdinfo->uas_tag - 1] = NULL; uas_free_unsubmitted_urbs(cmnd); cmnd->scsi_done(cmnd); return 0; @@ -289,7 +274,7 @@ static void uas_stat_cmplt(struct urb *urb) idx = be16_to_cpup(&iu->tag) - 1; if (idx >= MAX_CMNDS || !devinfo->cmnd[idx]) { dev_err(&urb->dev->dev, - "stat urb: no pending cmd for tag %d\n", idx + 1); + "stat urb: no pending cmd for uas-tag %d\n", idx + 1); goto out; } @@ -427,7 +412,8 @@ static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp, goto out; usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length, uas_data_cmplt, cmnd); - urb->stream_id = cmdinfo->stream; + if (devinfo->use_streams) + urb->stream_id = cmdinfo->uas_tag; urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0; urb->sg = sdb->table.sgl; out: @@ -451,7 +437,8 @@ static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp, usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu), uas_stat_cmplt, cmnd->device->host); - urb->stream_id = cmdinfo->stream; + if (devinfo->use_streams) + urb->stream_id = cmdinfo->uas_tag; urb->transfer_flags |= URB_FREE_BUFFER; out: return urb; @@ -465,6 +452,7 @@ static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp, { struct usb_device *udev = devinfo->udev; struct scsi_device *sdev = cmnd->device; + struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; struct urb *urb = usb_alloc_urb(0, gfp); struct command_iu *iu; int len; @@ -481,7 +469,7 @@ static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp, goto free; iu->iu_id = IU_ID_COMMAND; - iu->tag = cpu_to_be16(uas_get_tag(cmnd)); + iu->tag = cpu_to_be16(cmdinfo->uas_tag); iu->prio_attr = UAS_SIMPLE_TAG; iu->len = len; int_to_scsilun(sdev->lun, &iu->lun); @@ -608,8 +596,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, struct uas_dev_info *devinfo = sdev->hostdata; struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; unsigned long flags; - unsigned int stream; - int err; + int idx, err; BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer)); @@ -635,8 +622,12 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, return 0; } - stream = uas_get_tag(cmnd); - if (devinfo->cmnd[stream - 1]) { + /* Find a free uas-tag */ + for (idx = 0; idx < devinfo->qdepth; idx++) { + if (!devinfo->cmnd[idx]) + break; + } + if (idx == devinfo->qdepth) { spin_unlock_irqrestore(&devinfo->lock, flags); return SCSI_MLQUEUE_DEVICE_BUSY; } @@ -644,7 +635,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, cmnd->scsi_done = done; memset(cmdinfo, 0, sizeof(*cmdinfo)); - cmdinfo->stream = stream; + cmdinfo->uas_tag = idx + 1; /* uas-tag == usb-stream-id, so 1 based */ cmdinfo->state = SUBMIT_STATUS_URB | ALLOC_CMD_URB | SUBMIT_CMD_URB; switch (cmnd->sc_data_direction) { @@ -659,10 +650,8 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, break; } - if (!devinfo->use_streams) { + if (!devinfo->use_streams) cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB); - cmdinfo->stream = 0; - } err = uas_submit_urbs(cmnd, devinfo, GFP_ATOMIC); if (err) { @@ -674,7 +663,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, uas_add_work(cmdinfo); } - devinfo->cmnd[stream - 1] = cmnd; + devinfo->cmnd[idx] = cmnd; spin_unlock_irqrestore(&devinfo->lock, flags); return 0; } @@ -702,7 +691,7 @@ static int uas_eh_abort_handler(struct scsi_cmnd *cmnd) cmdinfo->state |= COMMAND_ABORTED; /* Drop all refs to this cmnd, kill data urbs to break their ref */ - devinfo->cmnd[uas_get_tag(cmnd) - 1] = NULL; + devinfo->cmnd[cmdinfo->uas_tag - 1] = NULL; if (cmdinfo->state & DATA_IN_URB_INFLIGHT) data_in_urb = usb_get_urb(cmdinfo->data_in_urb); if (cmdinfo->state & DATA_OUT_URB_INFLIGHT) @@ -799,8 +788,7 @@ static int uas_slave_configure(struct scsi_device *sdev) if (devinfo->flags & US_FL_NO_REPORT_OPCODES) sdev->no_report_opcodes = 1; - scsi_set_tag_type(sdev, MSG_ORDERED_TAG); - scsi_activate_tcq(sdev, devinfo->qdepth - 2); + scsi_change_queue_depth(sdev, devinfo->qdepth - 2); return 0; } @@ -817,14 +805,7 @@ static struct scsi_host_template uas_host_template = { .sg_tablesize = SG_NONE, .cmd_per_lun = 1, /* until we override it */ .skip_settle_delay = 1, - .ordered_tag = 1, - - /* - * The uas drivers expects tags not to be bigger than the maximum - * per-device queue depth, which is not true with the blk-mq tag - * allocator. - */ - .disable_blk_mq = true, + .use_blk_tags = 1, }; #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h index 8511b54a65d9..18a283d6de1c 100644 --- a/drivers/usb/storage/unusual_uas.h +++ b/drivers/usb/storage/unusual_uas.h @@ -54,6 +54,20 @@ UNUSUAL_DEV(0x0bc2, 0x3312, 0x0000, 0x9999, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NO_ATA_1X), +/* Reported-by: Hans de Goede <hdegoede@redhat.com> */ +UNUSUAL_DEV(0x0bc2, 0x3320, 0x0000, 0x9999, + "Seagate", + "Expansion Desk", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_NO_ATA_1X), + +/* Reported-by: Bogdan Mihalcea <bogdan.mihalcea@infim.ro> */ +UNUSUAL_DEV(0x0bc2, 0xa003, 0x0000, 0x9999, + "Seagate", + "Backup Plus", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_NO_ATA_1X), + /* https://bbs.archlinux.org/viewtopic.php?id=183190 */ UNUSUAL_DEV(0x0bc2, 0xab20, 0x0000, 0x9999, "Seagate", @@ -61,6 +75,13 @@ UNUSUAL_DEV(0x0bc2, 0xab20, 0x0000, 0x9999, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NO_ATA_1X), +/* https://bbs.archlinux.org/viewtopic.php?id=183190 */ +UNUSUAL_DEV(0x0bc2, 0xab21, 0x0000, 0x9999, + "Seagate", + "Backup+ BK", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_NO_ATA_1X), + /* Reported-by: Claudio Bizzarri <claudio.bizzarri@gmail.com> */ UNUSUAL_DEV(0x152d, 0x0567, 0x0000, 0x9999, "JMicron", @@ -75,3 +96,17 @@ UNUSUAL_DEV(0x174c, 0x5106, 0x0000, 0x9999, "ASM1051", USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_UAS), + +/* Reported-by: Hans de Goede <hdegoede@redhat.com> */ +UNUSUAL_DEV(0x2109, 0x0711, 0x0000, 0x9999, + "VIA", + "VL711", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_NO_ATA_1X), + +/* Reported-by: Hans de Goede <hdegoede@redhat.com> */ +UNUSUAL_DEV(0x4971, 0x1012, 0x0000, 0x9999, + "Hitachi", + "External HDD", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_IGNORE_UAS), diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 9d66ce62542e..d468d02179f4 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -884,7 +884,9 @@ static void usb_stor_scan_dwork(struct work_struct *work) dev_dbg(dev, "starting scan\n"); /* For bulk-only devices, determine the max LUN value */ - if (us->protocol == USB_PR_BULK && !(us->fflags & US_FL_SINGLE_LUN)) { + if (us->protocol == USB_PR_BULK && + !(us->fflags & US_FL_SINGLE_LUN) && + !(us->fflags & US_FL_SCM_MULT_TARG)) { mutex_lock(&us->dev_mutex); us->max_lun = usb_stor_Bulk_max_lun(us); mutex_unlock(&us->dev_mutex); @@ -983,21 +985,31 @@ int usb_stor_probe2(struct us_data *us) usb_stor_dbg(us, "Transport: %s\n", us->transport_name); usb_stor_dbg(us, "Protocol: %s\n", us->protocol_name); + if (us->fflags & US_FL_SCM_MULT_TARG) { + /* + * SCM eUSCSI bridge devices can have different numbers + * of LUNs on different targets; allow all to be probed. + */ + us->max_lun = 7; + /* The eUSCSI itself has ID 7, so avoid scanning that */ + us_to_host(us)->this_id = 7; + /* max_id is 8 initially, so no need to set it here */ + } else { + /* In the normal case there is only a single target */ + us_to_host(us)->max_id = 1; + /* + * Like Windows, we won't store the LUN bits in CDB[1] for + * SCSI-2 devices using the Bulk-Only transport (even though + * this violates the SCSI spec). + */ + if (us->transport == usb_stor_Bulk_transport) + us_to_host(us)->no_scsi2_lun_in_cdb = 1; + } + /* fix for single-lun devices */ if (us->fflags & US_FL_SINGLE_LUN) us->max_lun = 0; - if (!(us->fflags & US_FL_SCM_MULT_TARG)) - us_to_host(us)->max_id = 1; - - /* - * Like Windows, we won't store the LUN bits in CDB[1] for SCSI-2 - * devices using the Bulk-Only transport (even though this violates - * the SCSI spec). - */ - if (us->transport == usb_stor_Bulk_transport) - us_to_host(us)->no_scsi2_lun_in_cdb = 1; - /* Find the endpoints and calculate pipe values */ result = get_pipes(us); if (result) |