diff mbox series

[v10,17/33] scsi: sd: Fix sshdr use in sd_suspend_common

Message ID 20230714213419.95492-18-michael.christie@oracle.com
State Superseded
Headers show
Series scsi: Allow scsi_execute users to control retries | expand

Commit Message

Mike Christie July 14, 2023, 9:34 p.m. UTC
If scsi_execute_cmd returns < 0, it doesn't initialize the sshdr, so we
shouldn't access the sshdr. If it returns 0, then the cmd executed
successfully, so there is no need to check the sshdr. To avoid where
sd_suspend_common will access the sshdr but scsi_execute_cmd has
not initialized it and to allow sd_sync_cache to convert
device/host/status errors to -EXYZ values, this has sd_sync_cache
convert ILLEGAL_REQUEST to -EOPNOTSUPP. sd_suspend_common can then
check for that error instead of using a sshdr.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 drivers/scsi/sd.c | 37 +++++++++++++++++--------------------
 1 file changed, 17 insertions(+), 20 deletions(-)

Comments

John Garry July 25, 2023, 9:59 a.m. UTC | #1
> -
>   	for (retries = 3; retries > 0; --retries) {
>   		unsigned char cmd[16] = { 0 };
>   
> @@ -1645,15 +1642,19 @@ static int sd_sync_cache(struct scsi_disk *sdkp, struct scsi_sense_hdr *sshdr)
>   			return res;
>   
>   		if (scsi_status_is_check_condition(res) &&
> -		    scsi_sense_valid(sshdr)) {
> -			sd_print_sense_hdr(sdkp, sshdr);
> +		    scsi_sense_valid(&sshdr)) {
> +			sd_print_sense_hdr(sdkp, &sshdr);
>   
>   			/* we need to evaluate the error return  */
> -			if (sshdr->asc == 0x3a ||	/* medium not present */
> -			    sshdr->asc == 0x20 ||	/* invalid command */
> -			    (sshdr->asc == 0x74 && sshdr->ascq == 0x71))	/* drive is password locked */
> +			if (sshdr.asc == 0x3a ||	/* medium not present */
> +			    sshdr.asc == 0x20 ||	/* invalid command */
> +			    (sshdr.asc == 0x74 && sshdr.ascq == 0x71))	/* drive is password locked */
>   				/* this is no error here */
>   				return 0;
> +
> +			/* This drive doesn't support sync. */
> +			if (sshdr.sense_key == ILLEGAL_REQUEST)
> +				return -EOPNOTSUPP;

Only sd_suspend_common() interprets this, right? And in that case, it 
treats as if no error, so could you just return 0 here (and drop the 
-EOPNOTSUPP check in sd_suspend_common())?

Thanks,
John

>   		}
>   
>   		switch (host_byte(res)) {
> @@ -3848,7 +3849,7 @@ static void sd_shutdown(struct device *dev)
>   
>   	if (sdkp->WCE && sdkp->media_present) {
>   		sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n");
> -		sd_sync_cache(sdkp, NULL);
> +		sd_sync_cache(sdkp);
>   	}
>   
>   	if (system_state != SYSTEM_RESTART && sdkp->device->manage_start_stop) {
> @@ -3860,7 +3861,6 @@ static void sd_shutdown(struct device *dev)
>   static int sd_suspend_common(struct device *dev, bool ignore_stop_errors)
>   {
>   	struct scsi_disk *sdkp = dev_get_drvdata(dev);
> -	struct scsi_sense_hdr sshdr;
>   	int ret = 0;
>   
>   	if (!sdkp)	/* E.g.: runtime suspend following sd_remove() */
> @@ -3869,21 +3869,18 @@ static int sd_suspend_common(struct device *dev, bool ignore_stop_errors)
>   	if (sdkp->WCE && sdkp->media_present) {
>   		if (!sdkp->device->silence_suspend)
>   			sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n");
> -		ret = sd_sync_cache(sdkp, &sshdr);
> +		ret = sd_sync_cache(sdkp);
>   
>   		if (ret) {
>   			/* ignore OFFLINE device */
>   			if (ret == -ENODEV)
>   				return 0;
>   
> -			if (!scsi_sense_valid(&sshdr) ||
> -			    sshdr.sense_key != ILLEGAL_REQUEST)
> +			if (ret != -EOPNOTSUPP)
>   				return ret;
> -
>   			/*
> -			 * sshdr.sense_key == ILLEGAL_REQUEST means this drive
> -			 * doesn't support sync. There's not much to do and
> -			 * suspend shouldn't fail.
> +			 * The drive doesn't support sync. There's not much to
> +			 * do and suspend shouldn't fail.
>   			 */
>   			ret = 0;
>   		}
diff mbox series

Patch

diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 34a1149bfff2..1f110d646896 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1603,24 +1603,21 @@  static unsigned int sd_check_events(struct gendisk *disk, unsigned int clearing)
 	return disk_changed ? DISK_EVENT_MEDIA_CHANGE : 0;
 }
 
-static int sd_sync_cache(struct scsi_disk *sdkp, struct scsi_sense_hdr *sshdr)
+static int sd_sync_cache(struct scsi_disk *sdkp)
 {
 	int retries, res;
 	struct scsi_device *sdp = sdkp->device;
 	const int timeout = sdp->request_queue->rq_timeout
 		* SD_FLUSH_TIMEOUT_MULTIPLIER;
-	struct scsi_sense_hdr my_sshdr;
+	struct scsi_sense_hdr sshdr;
 	const struct scsi_exec_args exec_args = {
 		.req_flags = BLK_MQ_REQ_PM,
-		/* caller might not be interested in sense, but we need it */
-		.sshdr = sshdr ? : &my_sshdr,
+		.sshdr = &sshdr,
 	};
 
 	if (!scsi_device_online(sdp))
 		return -ENODEV;
 
-	sshdr = exec_args.sshdr;
-
 	for (retries = 3; retries > 0; --retries) {
 		unsigned char cmd[16] = { 0 };
 
@@ -1645,15 +1642,19 @@  static int sd_sync_cache(struct scsi_disk *sdkp, struct scsi_sense_hdr *sshdr)
 			return res;
 
 		if (scsi_status_is_check_condition(res) &&
-		    scsi_sense_valid(sshdr)) {
-			sd_print_sense_hdr(sdkp, sshdr);
+		    scsi_sense_valid(&sshdr)) {
+			sd_print_sense_hdr(sdkp, &sshdr);
 
 			/* we need to evaluate the error return  */
-			if (sshdr->asc == 0x3a ||	/* medium not present */
-			    sshdr->asc == 0x20 ||	/* invalid command */
-			    (sshdr->asc == 0x74 && sshdr->ascq == 0x71))	/* drive is password locked */
+			if (sshdr.asc == 0x3a ||	/* medium not present */
+			    sshdr.asc == 0x20 ||	/* invalid command */
+			    (sshdr.asc == 0x74 && sshdr.ascq == 0x71))	/* drive is password locked */
 				/* this is no error here */
 				return 0;
+
+			/* This drive doesn't support sync. */
+			if (sshdr.sense_key == ILLEGAL_REQUEST)
+				return -EOPNOTSUPP;
 		}
 
 		switch (host_byte(res)) {
@@ -3848,7 +3849,7 @@  static void sd_shutdown(struct device *dev)
 
 	if (sdkp->WCE && sdkp->media_present) {
 		sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n");
-		sd_sync_cache(sdkp, NULL);
+		sd_sync_cache(sdkp);
 	}
 
 	if (system_state != SYSTEM_RESTART && sdkp->device->manage_start_stop) {
@@ -3860,7 +3861,6 @@  static void sd_shutdown(struct device *dev)
 static int sd_suspend_common(struct device *dev, bool ignore_stop_errors)
 {
 	struct scsi_disk *sdkp = dev_get_drvdata(dev);
-	struct scsi_sense_hdr sshdr;
 	int ret = 0;
 
 	if (!sdkp)	/* E.g.: runtime suspend following sd_remove() */
@@ -3869,21 +3869,18 @@  static int sd_suspend_common(struct device *dev, bool ignore_stop_errors)
 	if (sdkp->WCE && sdkp->media_present) {
 		if (!sdkp->device->silence_suspend)
 			sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n");
-		ret = sd_sync_cache(sdkp, &sshdr);
+		ret = sd_sync_cache(sdkp);
 
 		if (ret) {
 			/* ignore OFFLINE device */
 			if (ret == -ENODEV)
 				return 0;
 
-			if (!scsi_sense_valid(&sshdr) ||
-			    sshdr.sense_key != ILLEGAL_REQUEST)
+			if (ret != -EOPNOTSUPP)
 				return ret;
-
 			/*
-			 * sshdr.sense_key == ILLEGAL_REQUEST means this drive
-			 * doesn't support sync. There's not much to do and
-			 * suspend shouldn't fail.
+			 * The drive doesn't support sync. There's not much to
+			 * do and suspend shouldn't fail.
 			 */
 			ret = 0;
 		}