Commit ab4b7164 authored by Bjørn Mork's avatar Bjørn Mork Committed by Greg Kroah-Hartman

USB: storage: fix Huawei mode switching regression

This reverts commit 200e0d99 ("USB: storage: optimize to match the
Huawei USB storage devices and support new switch command" and the
followup bugfix commit cd060956 ("USB: storage: properly handle
the endian issues of idProduct").

The commit effectively added a large number of Huawei devices to
the deprecated usb-storage mode switching logic.  Many of these
devices have been in use and supported by the userspace
usb_modeswitch utility for years.  Forcing the switching inside
the kernel causes a number of regressions as a result of ignoring
existing onfigurations, and also completely takes away the ability
to configure mode switching per device/system/user.

Known regressions caused by this:
 - Some of the devices support multiple modes, using different
  switching commands.  There are existing configurations taking
  advantage of this.

 - There is a real use case for disabling mode switching and
  instead mounting the exposed storage device. This becomes
  impossible with switching logic inside the usb-storage driver.

 - At least on device fail as a result of the usb-storage switching
  command, becoming completely unswitchable. This is possibly a
  firmware bug, but still a regression because the device work as
  expected using usb_modeswitch defaults.

In-kernel mode switching was deprecated years ago with the
development of the more user friendly userspace alternatives. The
existing list of devices in usb-storage was only kept to prevent
breaking already working systems.  The long term plan is to remove
the list, not to add to it. Ref:
http://permalink.gmane.org/gmane.linux.usb.general/28543

Cc: <fangxiaozhi@huawei.com>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: default avatarBjørn Mork <bjorn@mork.no>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent fbb8c745
......@@ -92,8 +92,8 @@ int usb_stor_ucr61s2b_init(struct us_data *us)
return 0;
}
/* This places the HUAWEI usb dongles in multi-port mode */
static int usb_stor_huawei_feature_init(struct us_data *us)
/* This places the HUAWEI E220 devices in multi-port mode */
int usb_stor_huawei_e220_init(struct us_data *us)
{
int result;
......@@ -104,75 +104,3 @@ static int usb_stor_huawei_feature_init(struct us_data *us)
US_DEBUGP("Huawei mode set result is %d\n", result);
return 0;
}
/*
* It will send a scsi switch command called rewind' to huawei dongle.
* When the dongle receives this command at the first time,
* it will reboot immediately. After rebooted, it will ignore this command.
* So it is unnecessary to read its response.
*/
static int usb_stor_huawei_scsi_init(struct us_data *us)
{
int result = 0;
int act_len = 0;
struct bulk_cb_wrap *bcbw = (struct bulk_cb_wrap *) us->iobuf;
char rewind_cmd[] = {0x11, 0x06, 0x20, 0x00, 0x00, 0x01, 0x01, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
bcbw->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcbw->Tag = 0;
bcbw->DataTransferLength = 0;
bcbw->Flags = bcbw->Lun = 0;
bcbw->Length = sizeof(rewind_cmd);
memset(bcbw->CDB, 0, sizeof(bcbw->CDB));
memcpy(bcbw->CDB, rewind_cmd, sizeof(rewind_cmd));
result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcbw,
US_BULK_CB_WRAP_LEN, &act_len);
US_DEBUGP("transfer actual length=%d, result=%d\n", act_len, result);
return result;
}
/*
* It tries to find the supported Huawei USB dongles.
* In Huawei, they assign the following product IDs
* for all of their mobile broadband dongles,
* including the new dongles in the future.
* So if the product ID is not included in this list,
* it means it is not Huawei's mobile broadband dongles.
*/
static int usb_stor_huawei_dongles_pid(struct us_data *us)
{
struct usb_interface_descriptor *idesc;
int idProduct;
idesc = &us->pusb_intf->cur_altsetting->desc;
idProduct = le16_to_cpu(us->pusb_dev->descriptor.idProduct);
/* The first port is CDROM,
* means the dongle in the single port mode,
* and a switch command is required to be sent. */
if (idesc && idesc->bInterfaceNumber == 0) {
if ((idProduct == 0x1001)
|| (idProduct == 0x1003)
|| (idProduct == 0x1004)
|| (idProduct >= 0x1401 && idProduct <= 0x1500)
|| (idProduct >= 0x1505 && idProduct <= 0x1600)
|| (idProduct >= 0x1c02 && idProduct <= 0x2202)) {
return 1;
}
}
return 0;
}
int usb_stor_huawei_init(struct us_data *us)
{
int result = 0;
if (usb_stor_huawei_dongles_pid(us)) {
if (le16_to_cpu(us->pusb_dev->descriptor.idProduct) >= 0x1446)
result = usb_stor_huawei_scsi_init(us);
else
result = usb_stor_huawei_feature_init(us);
}
return result;
}
......@@ -46,5 +46,5 @@ int usb_stor_euscsi_init(struct us_data *us);
* flash reader */
int usb_stor_ucr61s2b_init(struct us_data *us);
/* This places the HUAWEI usb dongles in multi-port mode */
int usb_stor_huawei_init(struct us_data *us);
/* This places the HUAWEI E220 devices in multi-port mode */
int usb_stor_huawei_e220_init(struct us_data *us);
This diff is collapsed.
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