summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan McLeran <daniel.mcleran@intel.com>2014-06-06 08:27:27 -0600
committerMatthew Wilcox <matthew.r.wilcox@intel.com>2014-06-13 13:11:00 -0400
commitb8e080847a7292347a3eee76264f77e4abcb61f7 (patch)
treeb80c4ea77518d15176b66cf165b1ddbfa8faa8aa
parentef351b97dedaa7a6e257ed4f554718e384d8786b (diff)
downloadop-kernel-dev-b8e080847a7292347a3eee76264f77e4abcb61f7.zip
op-kernel-dev-b8e080847a7292347a3eee76264f77e4abcb61f7.tar.gz
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>
-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 24308ae..a4cd6d6 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,
goto out_dma;
}
id_ctrl = mem;
- lowest_pow_st = id_ctrl->npss - 1;
+ lowest_pow_st = max(POWER_STATE_0, (int)(id_ctrl->npss - 1));
switch (pc) {
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,
break;
case NVME_POWER_STATE_IDLE:
/* Action unspecified if POWER CONDITION MODIFIER != [0,1,2] */
- /* min of desired state and (lps-1) because lps is STOP */
if (pcmod == 0x0)
- ps_desired = min(POWER_STATE_1, (lowest_pow_st - 1));
+ ps_desired = POWER_STATE_1;
else if (pcmod == 0x1)
- ps_desired = min(POWER_STATE_2, (lowest_pow_st - 1));
+ ps_desired = POWER_STATE_2;
else if (pcmod == 0x2)
- ps_desired = min(POWER_STATE_3, (lowest_pow_st - 1));
+ ps_desired = POWER_STATE_3;
break;
case NVME_POWER_STATE_STANDBY:
/* Action unspecified if POWER CONDITION MODIFIER != [0,1] */
if (pcmod == 0x0)
- ps_desired = max(0, (lowest_pow_st - 2));
+ ps_desired = max(POWER_STATE_0, (lowest_pow_st - 2));
else if (pcmod == 0x1)
- ps_desired = max(0, (lowest_pow_st - 1));
+ ps_desired = max(POWER_STATE_0, (lowest_pow_st - 1));
break;
case NVME_POWER_STATE_LU_CONTROL:
default:
OpenPOWER on IntegriCloud