From d2886ea368a67704ecc13e69075f18a9d74cb12b Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sun, 11 May 2008 00:34:07 +0200 Subject: scsi: sd: optionally set power condition in START STOP UNIT Adds a new scsi_device flag, start_stop_pwr_cond: If enabled, the sd driver will not send plain START STOP UNIT commands but ones with the power condition field set to 3 (standby) or 1 (active) respectively. Some FireWire disk firmwares do not stop the motor if power condition is zero. Or worse, they become unresponsive after a START STOP UNIT with power condition = 0 and start = 0. http://lkml.org/lkml/2008/4/29/704 This patch only adds the necessary code to sd_mod but doesn't activate it. Follow-up patches to the FireWire drivers will add detection of affected devices and enable the code for them. I did not add power condition values to scsi_error.c::scsi_eh_try_stu() for now. The three firmwares which suffer from above mentioned problems do not need START STOP UNIT in the error handler, and they are not adversely affected by START STOP UNIT with power condition = 0 and start = 1 (like scsi_eh_try_stu() sends it if scsi_device.allow_restart is enabled). Signed-off-by: Stefan Richter Tested-by: Tino Keitel diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 01cefbb..d53312c 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1124,6 +1124,8 @@ sd_spinup_disk(struct scsi_disk *sdkp) cmd[1] = 1; /* Return immediately */ memset((void *) &cmd[2], 0, 8); cmd[4] = 1; /* Start spin cycle */ + if (sdkp->device->start_stop_pwr_cond) + cmd[4] |= 1 << 4; scsi_execute_req(sdkp->device, cmd, DMA_NONE, NULL, 0, &sshdr, SD_TIMEOUT, SD_MAX_RETRIES); @@ -1790,6 +1792,9 @@ static int sd_start_stop_device(struct scsi_disk *sdkp, int start) if (start) cmd[4] |= 1; /* START */ + if (sdp->start_stop_pwr_cond) + cmd[4] |= start ? 1 << 4 : 3 << 4; /* Active or Standby */ + if (!scsi_device_online(sdp)) return -ENODEV; diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index f6a9fe0..00b7876 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -134,6 +134,7 @@ struct scsi_device { unsigned no_start_on_add:1; /* do not issue start on add */ unsigned allow_restart:1; /* issue START_UNIT in error handler */ unsigned manage_start_stop:1; /* Let HLD (sd) manage start/stop */ + unsigned start_stop_pwr_cond:1; /* Set power cond. in START_STOP_UNIT */ unsigned no_uld_attach:1; /* disable connecting to upper level drivers */ unsigned select_no_atn:1; unsigned fix_capacity:1; /* READ_CAPACITY is too high by 1 */ -- cgit v0.10.2 From ffcaade3109c3a4c0a2c601cf2a44d55b4c3af37 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sun, 11 May 2008 00:35:04 +0200 Subject: firewire: fw-sbp2: fix spindown for PL-3507 and TSB42AA9 firmwares Reported by Tino Keitel: PL-3507 with firmware from Prolific does not spin down the disk on START STOP UNIT with power condition = 0 and start = 0. It does however work with power condition = 2 or 3. Also found while investigating this: DViCO Momobay CX-1 and FX-3A (TI TSB42AA9/A based) become unresponsive after START STOP UNIT with power condition = 0 and start = 0. They stay responsive if power condition is set when stopping the motor. Signed-off-by: Stefan Richter Tested-by: Tino Keitel diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c index 227d2e0..bb8830f 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c @@ -86,6 +86,11 @@ MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device " * - delay inquiry * Wait extra SBP2_INQUIRY_DELAY seconds after login before SCSI inquiry. * + * - power condition + * Set the power condition field in the START STOP UNIT commands sent by + * sd_mod on suspend, resume, and shutdown (if manage_start_stop is on). + * Some disks need this to spin down or to resume properly. + * * - override internal blacklist * Instead of adding to the built-in blacklist, use only the workarounds * specified in the module load parameter. @@ -97,6 +102,7 @@ MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device " #define SBP2_WORKAROUND_FIX_CAPACITY 0x8 #define SBP2_WORKAROUND_DELAY_INQUIRY 0x10 #define SBP2_INQUIRY_DELAY 12 +#define SBP2_WORKAROUND_POWER_CONDITION 0x20 #define SBP2_WORKAROUND_OVERRIDE 0x100 static int sbp2_param_workarounds; @@ -107,6 +113,8 @@ MODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0" ", skip mode page 8 = " __stringify(SBP2_WORKAROUND_MODE_SENSE_8) ", fix capacity = " __stringify(SBP2_WORKAROUND_FIX_CAPACITY) ", delay inquiry = " __stringify(SBP2_WORKAROUND_DELAY_INQUIRY) + ", set power condition in start stop unit = " + __stringify(SBP2_WORKAROUND_POWER_CONDITION) ", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE) ", or a combination)"); @@ -310,18 +318,25 @@ static const struct { .firmware_revision = 0x002800, .model = 0x001010, .workarounds = SBP2_WORKAROUND_INQUIRY_36 | - SBP2_WORKAROUND_MODE_SENSE_8, + SBP2_WORKAROUND_MODE_SENSE_8 | + SBP2_WORKAROUND_POWER_CONDITION, }, /* DViCO Momobay FX-3A with TSB42AA9A bridge */ { .firmware_revision = 0x002800, .model = 0x000000, - .workarounds = SBP2_WORKAROUND_DELAY_INQUIRY, + .workarounds = SBP2_WORKAROUND_DELAY_INQUIRY | + SBP2_WORKAROUND_POWER_CONDITION, }, /* Initio bridges, actually only needed for some older ones */ { .firmware_revision = 0x000200, .model = ~0, .workarounds = SBP2_WORKAROUND_INQUIRY_36, }, + /* PL-3507 bridge with Prolific firmware */ { + .firmware_revision = 0x012800, + .model = ~0, + .workarounds = SBP2_WORKAROUND_POWER_CONDITION, + }, /* Symbios bridge */ { .firmware_revision = 0xa0b800, .model = ~0, @@ -1540,6 +1555,9 @@ static int sbp2_scsi_slave_configure(struct scsi_device *sdev) if (lu->tgt->workarounds & SBP2_WORKAROUND_FIX_CAPACITY) sdev->fix_capacity = 1; + if (lu->tgt->workarounds & SBP2_WORKAROUND_POWER_CONDITION) + sdev->start_stop_pwr_cond = 1; + if (lu->tgt->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS) blk_queue_max_sectors(sdev->request_queue, 128 * 1024 / 512); -- cgit v0.10.2 From 3719122a520af2957031859317e74858ab4d3f4b Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sun, 11 May 2008 00:35:55 +0200 Subject: ieee1394: sbp2: fix spindown for PL-3507 and TSB42AA9 firmwares Reported by Tino Keitel: PL-3507 with firmware from Prolific does not spin down the disk on START STOP UNIT with power condition = 0 and start = 0. It does however work with power condition = 2 or 3. Also found while investigating this: DViCO Momobay CX-1 and FX-3A (TI TSB42AA9/A based) become unresponsive after START STOP UNIT with power condition = 0 and start = 0. They stay responsive if power condition is set when stopping the motor. Signed-off-by: Stefan Richter diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c index a5ceff2..219164d 100644 --- a/drivers/ieee1394/sbp2.c +++ b/drivers/ieee1394/sbp2.c @@ -186,6 +186,11 @@ MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device " * - delay inquiry * Wait extra SBP2_INQUIRY_DELAY seconds after login before SCSI inquiry. * + * - power condition + * Set the power condition field in the START STOP UNIT commands sent by + * sd_mod on suspend, resume, and shutdown (if manage_start_stop is on). + * Some disks need this to spin down or to resume properly. + * * - override internal blacklist * Instead of adding to the built-in blacklist, use only the workarounds * specified in the module load parameter. @@ -199,6 +204,8 @@ MODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0" ", skip mode page 8 = " __stringify(SBP2_WORKAROUND_MODE_SENSE_8) ", fix capacity = " __stringify(SBP2_WORKAROUND_FIX_CAPACITY) ", delay inquiry = " __stringify(SBP2_WORKAROUND_DELAY_INQUIRY) + ", set power condition in start stop unit = " + __stringify(SBP2_WORKAROUND_POWER_CONDITION) ", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE) ", or a combination)"); @@ -359,18 +366,25 @@ static const struct { .firmware_revision = 0x002800, .model_id = 0x001010, .workarounds = SBP2_WORKAROUND_INQUIRY_36 | - SBP2_WORKAROUND_MODE_SENSE_8, + SBP2_WORKAROUND_MODE_SENSE_8 | + SBP2_WORKAROUND_POWER_CONDITION, }, /* DViCO Momobay FX-3A with TSB42AA9A bridge */ { .firmware_revision = 0x002800, .model_id = 0x000000, - .workarounds = SBP2_WORKAROUND_DELAY_INQUIRY, + .workarounds = SBP2_WORKAROUND_DELAY_INQUIRY | + SBP2_WORKAROUND_POWER_CONDITION, }, /* Initio bridges, actually only needed for some older ones */ { .firmware_revision = 0x000200, .model_id = SBP2_ROM_VALUE_WILDCARD, .workarounds = SBP2_WORKAROUND_INQUIRY_36, }, + /* PL-3507 bridge with Prolific firmware */ { + .firmware_revision = 0x012800, + .model_id = SBP2_ROM_VALUE_WILDCARD, + .workarounds = SBP2_WORKAROUND_POWER_CONDITION, + }, /* Symbios bridge */ { .firmware_revision = 0xa0b800, .model_id = SBP2_ROM_VALUE_WILDCARD, @@ -2002,6 +2016,8 @@ static int sbp2scsi_slave_configure(struct scsi_device *sdev) sdev->skip_ms_page_8 = 1; if (lu->workarounds & SBP2_WORKAROUND_FIX_CAPACITY) sdev->fix_capacity = 1; + if (lu->workarounds & SBP2_WORKAROUND_POWER_CONDITION) + sdev->start_stop_pwr_cond = 1; if (lu->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS) blk_queue_max_sectors(sdev->request_queue, 128 * 1024 / 512); return 0; diff --git a/drivers/ieee1394/sbp2.h b/drivers/ieee1394/sbp2.h index 80d8e09..875428b 100644 --- a/drivers/ieee1394/sbp2.h +++ b/drivers/ieee1394/sbp2.h @@ -345,6 +345,7 @@ enum sbp2lu_state_types { #define SBP2_WORKAROUND_FIX_CAPACITY 0x8 #define SBP2_WORKAROUND_DELAY_INQUIRY 0x10 #define SBP2_INQUIRY_DELAY 12 +#define SBP2_WORKAROUND_POWER_CONDITION 0x20 #define SBP2_WORKAROUND_OVERRIDE 0x100 #endif /* SBP2_H */ -- cgit v0.10.2 From 2635f96f9086409de0ec882a210f374c012bffc3 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sun, 11 May 2008 00:36:47 +0200 Subject: firewire: fw-sbp2: spin disks down on suspend and shutdown This instructs sd_mod to send START STOP UNIT on suspend and resume, and on driver unbinding or unloading (including when the system is shut down). We don't do this though if multiple initiators may log in to the target. Signed-off-by: Stefan Richter Tested-by: Tino Keitel diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c index bb8830f..53fc5a6 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c @@ -1545,6 +1545,9 @@ static int sbp2_scsi_slave_configure(struct scsi_device *sdev) sdev->use_10_for_rw = 1; + if (sbp2_param_exclusive_login) + sdev->manage_start_stop = 1; + if (sdev->type == TYPE_ROM) sdev->use_10_for_ms = 1; -- cgit v0.10.2 From 82f06e86117680ada35fdb76c8852268d994cd99 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sun, 11 May 2008 00:37:14 +0200 Subject: ieee1394: sbp2: spin disks down on suspend and shutdown This instructs sd_mod to send START STOP UNIT on suspend and resume, and on driver unbinding or unloading (including when the system is shut down). We don't do this though if multiple initiators may log in to the target. Signed-off-by: Stefan Richter diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c index 219164d..9cbf315 100644 --- a/drivers/ieee1394/sbp2.c +++ b/drivers/ieee1394/sbp2.c @@ -2009,6 +2009,8 @@ static int sbp2scsi_slave_configure(struct scsi_device *sdev) sdev->use_10_for_rw = 1; + if (sbp2_exclusive_login) + sdev->manage_start_stop = 1; if (sdev->type == TYPE_ROM) sdev->use_10_for_ms = 1; if (sdev->type == TYPE_DISK && -- cgit v0.10.2