Skip to content

Commit b8a5376

Browse files
kelleymhliuw
authored andcommitted
scsi: storvsc: Fix handling of srb_status and capacity change events
Current handling of the srb_status is incorrect. Commit 52e1b3b ("scsi: storvsc: Correctly handle multiple flags in srb_status") is based on srb_status being a set of flags, when in fact only the 2 high order bits are flags and the remaining 6 bits are an integer status. Because the integer values of interest mostly look like flags, the code actually works when treated that way. But in the interest of correctness going forward, fix this by treating the low 6 bits of srb_status as an integer status code. Add handling for SRB_STATUS_INVALID_REQUEST, which was the original intent of commit 52e1b3b. Furthermore, treat the ERROR, ABORTED, and INVALID_REQUEST srb status codes as essentially equivalent for the cases we care about. There's no harm in doing so, and it isn't always clear which status code current or older versions of Hyper-V report for particular conditions. Treating the srb status codes as equivalent has the additional benefit of ensuring that capacity change events result in an immediate rescan so that the new size is known to Linux. Existing code checks SCSI sense data for capacity change events when the srb status is ABORTED. But capacity change events are also being observed when Hyper-V reports the srb status as ERROR. Without the immediate rescan, the new size isn't known until something else causes a rescan (such as running fdisk to expand a partition), and in the meantime, tools such as "lsblk" continue to report the old size. Fixes: 52e1b3b ("scsi: storvsc: Correctly handle multiple flags in srb_status") Reported-by: Juan Tian <[email protected]> Signed-off-by: Michael Kelley <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Wei Liu <[email protected]>
1 parent ee68154 commit b8a5376

File tree

1 file changed

+34
-35
lines changed

1 file changed

+34
-35
lines changed

drivers/scsi/storvsc_drv.c

Lines changed: 34 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -303,16 +303,21 @@ enum storvsc_request_type {
303303
};
304304

305305
/*
306-
* SRB status codes and masks; a subset of the codes used here.
306+
* SRB status codes and masks. In the 8-bit field, the two high order bits
307+
* are flags, while the remaining 6 bits are an integer status code. The
308+
* definitions here include only the subset of the integer status codes that
309+
* are tested for in this driver.
307310
*/
308-
309311
#define SRB_STATUS_AUTOSENSE_VALID 0x80
310312
#define SRB_STATUS_QUEUE_FROZEN 0x40
311-
#define SRB_STATUS_INVALID_LUN 0x20
312-
#define SRB_STATUS_SUCCESS 0x01
313-
#define SRB_STATUS_ABORTED 0x02
314-
#define SRB_STATUS_ERROR 0x04
315-
#define SRB_STATUS_DATA_OVERRUN 0x12
313+
314+
/* SRB status integer codes */
315+
#define SRB_STATUS_SUCCESS 0x01
316+
#define SRB_STATUS_ABORTED 0x02
317+
#define SRB_STATUS_ERROR 0x04
318+
#define SRB_STATUS_INVALID_REQUEST 0x06
319+
#define SRB_STATUS_DATA_OVERRUN 0x12
320+
#define SRB_STATUS_INVALID_LUN 0x20
316321

317322
#define SRB_STATUS(status) \
318323
(status & ~(SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_QUEUE_FROZEN))
@@ -969,38 +974,25 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb,
969974
void (*process_err_fn)(struct work_struct *work);
970975
struct hv_host_device *host_dev = shost_priv(host);
971976

972-
/*
973-
* In some situations, Hyper-V sets multiple bits in the
974-
* srb_status, such as ABORTED and ERROR. So process them
975-
* individually, with the most specific bits first.
976-
*/
977-
978-
if (vm_srb->srb_status & SRB_STATUS_INVALID_LUN) {
979-
set_host_byte(scmnd, DID_NO_CONNECT);
980-
process_err_fn = storvsc_remove_lun;
981-
goto do_work;
982-
}
977+
switch (SRB_STATUS(vm_srb->srb_status)) {
978+
case SRB_STATUS_ERROR:
979+
case SRB_STATUS_ABORTED:
980+
case SRB_STATUS_INVALID_REQUEST:
981+
if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID) {
982+
/* Check for capacity change */
983+
if ((asc == 0x2a) && (ascq == 0x9)) {
984+
process_err_fn = storvsc_device_scan;
985+
/* Retry the I/O that triggered this. */
986+
set_host_byte(scmnd, DID_REQUEUE);
987+
goto do_work;
988+
}
983989

984-
if (vm_srb->srb_status & SRB_STATUS_ABORTED) {
985-
if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID &&
986-
/* Capacity data has changed */
987-
(asc == 0x2a) && (ascq == 0x9)) {
988-
process_err_fn = storvsc_device_scan;
989990
/*
990-
* Retry the I/O that triggered this.
991+
* Otherwise, let upper layer deal with the
992+
* error when sense message is present
991993
*/
992-
set_host_byte(scmnd, DID_REQUEUE);
993-
goto do_work;
994-
}
995-
}
996-
997-
if (vm_srb->srb_status & SRB_STATUS_ERROR) {
998-
/*
999-
* Let upper layer deal with error when
1000-
* sense message is present.
1001-
*/
1002-
if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID)
1003994
return;
995+
}
1004996

1005997
/*
1006998
* If there is an error; offline the device since all
@@ -1023,6 +1015,13 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb,
10231015
default:
10241016
set_host_byte(scmnd, DID_ERROR);
10251017
}
1018+
return;
1019+
1020+
case SRB_STATUS_INVALID_LUN:
1021+
set_host_byte(scmnd, DID_NO_CONNECT);
1022+
process_err_fn = storvsc_remove_lun;
1023+
goto do_work;
1024+
10261025
}
10271026
return;
10281027

0 commit comments

Comments
 (0)