aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/nvme-scsi.c
diff options
context:
space:
mode:
authorDan McLeran <daniel.mcleran@intel.com>2014-06-06 10:27:27 -0400
committerMatthew Wilcox <matthew.r.wilcox@intel.com>2014-06-13 13:11:00 -0400
commitb8e080847a7292347a3eee76264f77e4abcb61f7 (patch)
treeb80c4ea77518d15176b66cf165b1ddbfa8faa8aa /drivers/block/nvme-scsi.c
parentef351b97dedaa7a6e257ed4f554718e384d8786b (diff)
NVMe: Fix START_STOP_UNIT Scsi->NVMe translation.
This patch contains several fixes for Scsi START_STOP_UNIT. The previous code did not account for signed vs. unsigned arithmetic which resulted in an invalid lowest power state caculation when the device only supports 1 power state. The code for Power Condition == 2 (Idle) was not following the spec. The spec calls for setting the device to specific power states, depending upon Power Condition Modifier, without accounting for the number of power states supported by the device. The code for Power Condition == 3 (Standby) was using a hard-coded '0' which is replaced with the macro POWER_STATE_0. Signed-off-by: Dan McLeran <daniel.mcleran@intel.com> Reviewed-by: Vishal Verma <vishal.l.verma@linux.intel.com> Signed-off-by: Matthew Wilcox <matthew.r.wilcox@intel.com>
Diffstat (limited to 'drivers/block/nvme-scsi.c')
-rw-r--r--drivers/block/nvme-scsi.c13
1 files changed, 6 insertions, 7 deletions
diff --git a/drivers/block/nvme-scsi.c b/drivers/block/nvme-scsi.c
index 24308ae8abf5..a4cd6d691c63 100644
--- a/drivers/block/nvme-scsi.c
+++ b/drivers/block/nvme-scsi.c
@@ -1476,7 +1476,7 @@ static int nvme_trans_power_state(struct nvme_ns *ns, struct sg_io_hdr *hdr,
1476 goto out_dma; 1476 goto out_dma;
1477 } 1477 }
1478 id_ctrl = mem; 1478 id_ctrl = mem;
1479 lowest_pow_st = id_ctrl->npss - 1; 1479 lowest_pow_st = max(POWER_STATE_0, (int)(id_ctrl->npss - 1));
1480 1480
1481 switch (pc) { 1481 switch (pc) {
1482 case NVME_POWER_STATE_START_VALID: 1482 case NVME_POWER_STATE_START_VALID:
@@ -1493,20 +1493,19 @@ static int nvme_trans_power_state(struct nvme_ns *ns, struct sg_io_hdr *hdr,
1493 break; 1493 break;
1494 case NVME_POWER_STATE_IDLE: 1494 case NVME_POWER_STATE_IDLE:
1495 /* Action unspecified if POWER CONDITION MODIFIER != [0,1,2] */ 1495 /* Action unspecified if POWER CONDITION MODIFIER != [0,1,2] */
1496 /* min of desired state and (lps-1) because lps is STOP */
1497 if (pcmod == 0x0) 1496 if (pcmod == 0x0)
1498 ps_desired = min(POWER_STATE_1, (lowest_pow_st - 1)); 1497 ps_desired = POWER_STATE_1;
1499 else if (pcmod == 0x1) 1498 else if (pcmod == 0x1)
1500 ps_desired = min(POWER_STATE_2, (lowest_pow_st - 1)); 1499 ps_desired = POWER_STATE_2;
1501 else if (pcmod == 0x2) 1500 else if (pcmod == 0x2)
1502 ps_desired = min(POWER_STATE_3, (lowest_pow_st - 1)); 1501 ps_desired = POWER_STATE_3;
1503 break; 1502 break;
1504 case NVME_POWER_STATE_STANDBY: 1503 case NVME_POWER_STATE_STANDBY:
1505 /* Action unspecified if POWER CONDITION MODIFIER != [0,1] */ 1504 /* Action unspecified if POWER CONDITION MODIFIER != [0,1] */
1506 if (pcmod == 0x0) 1505 if (pcmod == 0x0)
1507 ps_desired = max(0, (lowest_pow_st - 2)); 1506 ps_desired = max(POWER_STATE_0, (lowest_pow_st - 2));
1508 else if (pcmod == 0x1) 1507 else if (pcmod == 0x1)
1509 ps_desired = max(0, (lowest_pow_st - 1)); 1508 ps_desired = max(POWER_STATE_0, (lowest_pow_st - 1));
1510 break; 1509 break;
1511 case NVME_POWER_STATE_LU_CONTROL: 1510 case NVME_POWER_STATE_LU_CONTROL:
1512 default: 1511 default: