Commit 59307852 authored by Hans de Goede's avatar Hans de Goede Committed by Greg Kroah-Hartman

uas: Add a quirk for rejecting ATA_12 and ATA_16 commands

And set this quirk for the Seagate Expansion Desk (0bc2:2312), as that one
seems to hang upon receiving an ATA_12 or ATA_16 command.

https://bugzilla.kernel.org/show_bug.cgi?id=79511
https://bbs.archlinux.org/viewtopic.php?id=183190

While at it also add missing documentation for the u value for usb-storage
quirks.

Cc: stable@vger.kernel.org # 3.16, 3.17
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>

--
Changes in v2: Add documentation for new t and u usb-storage.quirks flags
Changes in v3: Fix typo in documentation
Changes in v4: Also apply the quirk to (0bc2:3312)
Changes in v5: Rebased on 3.17-rc5, drop u documentation, already upstream
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent ab945eff
...@@ -3541,6 +3541,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ...@@ -3541,6 +3541,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
bogus residue values); bogus residue values);
s = SINGLE_LUN (the device has only one s = SINGLE_LUN (the device has only one
Logical Unit); Logical Unit);
t = NO_ATA_1X (don't allow ATA(12) and ATA(16)
commands, uas only);
u = IGNORE_UAS (don't bind to the uas driver); u = IGNORE_UAS (don't bind to the uas driver);
w = NO_WP_DETECT (don't test whether the w = NO_WP_DETECT (don't test whether the
medium is write-protected). medium is write-protected).
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <scsi/scsi_tcq.h> #include <scsi/scsi_tcq.h>
#include "uas-detect.h" #include "uas-detect.h"
#include "scsiglue.h"
/* /*
* The r00-r01c specs define this version of the SENSE IU data structure. * The r00-r01c specs define this version of the SENSE IU data structure.
...@@ -49,6 +50,7 @@ struct uas_dev_info { ...@@ -49,6 +50,7 @@ struct uas_dev_info {
struct usb_anchor cmd_urbs; struct usb_anchor cmd_urbs;
struct usb_anchor sense_urbs; struct usb_anchor sense_urbs;
struct usb_anchor data_urbs; struct usb_anchor data_urbs;
unsigned long flags;
int qdepth, resetting; int qdepth, resetting;
struct response_iu response; struct response_iu response;
unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe; unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe;
...@@ -714,6 +716,15 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, ...@@ -714,6 +716,15 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer)); BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer));
if ((devinfo->flags & US_FL_NO_ATA_1X) &&
(cmnd->cmnd[0] == ATA_12 || cmnd->cmnd[0] == ATA_16)) {
memcpy(cmnd->sense_buffer, usb_stor_sense_invalidCDB,
sizeof(usb_stor_sense_invalidCDB));
cmnd->result = SAM_STAT_CHECK_CONDITION;
cmnd->scsi_done(cmnd);
return 0;
}
spin_lock_irqsave(&devinfo->lock, flags); spin_lock_irqsave(&devinfo->lock, flags);
if (devinfo->resetting) { if (devinfo->resetting) {
...@@ -1080,6 +1091,8 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id) ...@@ -1080,6 +1091,8 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
devinfo->resetting = 0; devinfo->resetting = 0;
devinfo->running_task = 0; devinfo->running_task = 0;
devinfo->shutdown = 0; devinfo->shutdown = 0;
devinfo->flags = id->driver_info;
usb_stor_adjust_quirks(udev, &devinfo->flags);
init_usb_anchor(&devinfo->cmd_urbs); init_usb_anchor(&devinfo->cmd_urbs);
init_usb_anchor(&devinfo->sense_urbs); init_usb_anchor(&devinfo->sense_urbs);
init_usb_anchor(&devinfo->data_urbs); init_usb_anchor(&devinfo->data_urbs);
......
...@@ -40,13 +40,16 @@ ...@@ -40,13 +40,16 @@
* and don't forget to CC: the USB development list <linux-usb@vger.kernel.org> * and don't forget to CC: the USB development list <linux-usb@vger.kernel.org>
*/ */
/* /* https://bugzilla.kernel.org/show_bug.cgi?id=79511 */
* This is an example entry for the US_FL_IGNORE_UAS flag. Once we have an UNUSUAL_DEV(0x0bc2, 0x2312, 0x0000, 0x9999,
* actual entry using US_FL_IGNORE_UAS this entry should be removed. "Seagate",
* "Expansion Desk",
* UNUSUAL_DEV( 0xabcd, 0x1234, 0x0100, 0x0100, USB_SC_DEVICE, USB_PR_DEVICE, NULL,
* "Example", US_FL_NO_ATA_1X),
* "Storage with broken UAS",
* USB_SC_DEVICE, USB_PR_DEVICE, NULL, /* https://bbs.archlinux.org/viewtopic.php?id=183190 */
* US_FL_IGNORE_UAS), UNUSUAL_DEV(0x0bc2, 0x3312, 0x0000, 0x9999,
*/ "Seagate",
"Expansion Desk",
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_NO_ATA_1X),
...@@ -478,7 +478,8 @@ void usb_stor_adjust_quirks(struct usb_device *udev, unsigned long *fflags) ...@@ -478,7 +478,8 @@ void usb_stor_adjust_quirks(struct usb_device *udev, unsigned long *fflags)
US_FL_CAPACITY_OK | US_FL_IGNORE_RESIDUE | US_FL_CAPACITY_OK | US_FL_IGNORE_RESIDUE |
US_FL_SINGLE_LUN | US_FL_NO_WP_DETECT | US_FL_SINGLE_LUN | US_FL_NO_WP_DETECT |
US_FL_NO_READ_DISC_INFO | US_FL_NO_READ_CAPACITY_16 | US_FL_NO_READ_DISC_INFO | US_FL_NO_READ_CAPACITY_16 |
US_FL_INITIAL_READ10 | US_FL_WRITE_CACHE); US_FL_INITIAL_READ10 | US_FL_WRITE_CACHE |
US_FL_NO_ATA_1X);
p = quirks; p = quirks;
while (*p) { while (*p) {
...@@ -543,6 +544,9 @@ void usb_stor_adjust_quirks(struct usb_device *udev, unsigned long *fflags) ...@@ -543,6 +544,9 @@ void usb_stor_adjust_quirks(struct usb_device *udev, unsigned long *fflags)
case 's': case 's':
f |= US_FL_SINGLE_LUN; f |= US_FL_SINGLE_LUN;
break; break;
case 't':
f |= US_FL_NO_ATA_1X;
break;
case 'u': case 'u':
f |= US_FL_IGNORE_UAS; f |= US_FL_IGNORE_UAS;
break; break;
......
...@@ -73,6 +73,8 @@ ...@@ -73,6 +73,8 @@
/* Device advertises UAS but it is broken */ \ /* Device advertises UAS but it is broken */ \
US_FLAG(BROKEN_FUA, 0x01000000) \ US_FLAG(BROKEN_FUA, 0x01000000) \
/* Cannot handle FUA in WRITE or READ CDBs */ \ /* Cannot handle FUA in WRITE or READ CDBs */ \
US_FLAG(NO_ATA_1X, 0x02000000) \
/* Cannot handle ATA_12 or ATA_16 CDBs */ \
#define US_FLAG(name, value) US_FL_##name = value , #define US_FLAG(name, value) US_FL_##name = value ,
enum { US_DO_ALL_FLAGS }; enum { US_DO_ALL_FLAGS };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment