Commit b8e08084 authored by Dan McLeran's avatar Dan McLeran Committed by Matthew Wilcox

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: default avatarDan McLeran <daniel.mcleran@intel.com>
Reviewed-by: default avatarVishal Verma <vishal.l.verma@linux.intel.com>
Signed-off-by: default avatarMatthew Wilcox <matthew.r.wilcox@intel.com>
parent ef351b97
...@@ -1476,7 +1476,7 @@ static int nvme_trans_power_state(struct nvme_ns *ns, struct sg_io_hdr *hdr, ...@@ -1476,7 +1476,7 @@ static int nvme_trans_power_state(struct nvme_ns *ns, struct sg_io_hdr *hdr,
goto out_dma; goto out_dma;
} }
id_ctrl = mem; id_ctrl = mem;
lowest_pow_st = id_ctrl->npss - 1; lowest_pow_st = max(POWER_STATE_0, (int)(id_ctrl->npss - 1));
switch (pc) { switch (pc) {
case NVME_POWER_STATE_START_VALID: 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,20 +1493,19 @@ static int nvme_trans_power_state(struct nvme_ns *ns, struct sg_io_hdr *hdr,
break; break;
case NVME_POWER_STATE_IDLE: case NVME_POWER_STATE_IDLE:
/* Action unspecified if POWER CONDITION MODIFIER != [0,1,2] */ /* Action unspecified if POWER CONDITION MODIFIER != [0,1,2] */
/* min of desired state and (lps-1) because lps is STOP */
if (pcmod == 0x0) if (pcmod == 0x0)
ps_desired = min(POWER_STATE_1, (lowest_pow_st - 1)); ps_desired = POWER_STATE_1;
else if (pcmod == 0x1) else if (pcmod == 0x1)
ps_desired = min(POWER_STATE_2, (lowest_pow_st - 1)); ps_desired = POWER_STATE_2;
else if (pcmod == 0x2) else if (pcmod == 0x2)
ps_desired = min(POWER_STATE_3, (lowest_pow_st - 1)); ps_desired = POWER_STATE_3;
break; break;
case NVME_POWER_STATE_STANDBY: case NVME_POWER_STATE_STANDBY:
/* Action unspecified if POWER CONDITION MODIFIER != [0,1] */ /* Action unspecified if POWER CONDITION MODIFIER != [0,1] */
if (pcmod == 0x0) 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) else if (pcmod == 0x1)
ps_desired = max(0, (lowest_pow_st - 1)); ps_desired = max(POWER_STATE_0, (lowest_pow_st - 1));
break; break;
case NVME_POWER_STATE_LU_CONTROL: case NVME_POWER_STATE_LU_CONTROL:
default: default:
......
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