git: 6f840e49af37 - stable/13 - cam: Optimize write protection MODE SENSE in da(4).

From: Alexander Motin <mav_at_FreeBSD.org>
Date: Fri, 28 Jan 2022 00:25:50 UTC
The branch stable/13 has been updated by mav:

URL: https://cgit.FreeBSD.org/src/commit/?id=6f840e49af37ac3437957f30d6e45279316298dd

commit 6f840e49af37ac3437957f30d6e45279316298dd
Author:     Alexander Motin <mav@FreeBSD.org>
AuthorDate: 2022-01-14 22:48:19 +0000
Commit:     Alexander Motin <mav@FreeBSD.org>
CommitDate: 2022-01-28 00:25:45 +0000

    cam: Optimize write protection MODE SENSE in da(4).
    
    Before this change on every open da(4) driver read all mode pages to
    use only one bit.  It was done so to not depend on the list of pages
    supported by the disk.  But I've found that at least for SATL of LSI/
    Broadcom HBAs with WD HDDs Power Condition mode page reading may take
    significant amount of time, much more than any other mode page, that
    visibly increased disk retaste time by GEOM.
    
    Address that by using data returned by the first MODE SENSE request
    to limit the following ones to only one (the first for now) mode page.
    
    With the change simultaneous retaste of 39 SATA disks takes about 2.5s
    instead of more than 4s before, and I no longer see "dareprobe" status
    on GEOM event thread.
    
    MFC after:      2 weeks
    Sponsored by:   iXsystems, Inc.
    
    (cherry picked from commit a9a2cdaf3c193ee1b597d0eef51544636421d973)
---
 sys/cam/scsi/scsi_da.c | 41 +++++++++++++++++++++++++++++------------
 1 file changed, 29 insertions(+), 12 deletions(-)

diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c
index a5f0198468f5..f710e82eda9b 100644
--- a/sys/cam/scsi/scsi_da.c
+++ b/sys/cam/scsi/scsi_da.c
@@ -345,6 +345,7 @@ struct da_softc {
 	da_flags flags;
 	da_quirks quirks;
 	int	 minimum_cmd_size;
+	int	 mode_page;
 	int	 error_inject;
 	int	 trim_max_ranges;
 	int	 delete_available;	/* Delete methods possibly available */
@@ -2895,6 +2896,9 @@ daregister(struct cam_periph *periph, void *arg)
 	else
 		softc->minimum_cmd_size = 6;
 
+	/* On first PROBE_WP request all more pages, then adjust. */
+	softc->mode_page = SMS_ALL_PAGES_PAGE;
+
 	/* Predict whether device may support READ CAPACITY(16). */
 	if (SID_ANSI_REV(&cgd->inq_data) >= SCSI_REV_SPC3 &&
 	    (softc->quirks & DA_Q_NO_RC16) == 0) {
@@ -3488,7 +3492,7 @@ out:
 		void  *mode_buf;
 		int    mode_buf_len;
 
-		if (da_disable_wp_detection) {
+		if (da_disable_wp_detection || softc->mode_page < 0) {
 			if ((softc->flags & DA_FLAG_CAN_RC16) != 0)
 				softc->state = DA_STATE_PROBE_RC16;
 			else
@@ -3512,7 +3516,7 @@ out:
 				    /*tag_action*/ MSG_SIMPLE_Q_TAG,
 				    /*dbd*/ FALSE,
 				    /*pc*/ SMS_PAGE_CTRL_CURRENT,
-				    /*page*/ SMS_ALL_PAGES_PAGE,
+				    /*page*/ softc->mode_page,
 				    /*param_buf*/ mode_buf,
 				    /*param_len*/ mode_buf_len,
 				    /*minimum_cmd_size*/ softc->minimum_cmd_size,
@@ -4672,12 +4676,9 @@ dadone(struct cam_periph *periph, union ccb *done_ccb)
 static void
 dadone_probewp(struct cam_periph *periph, union ccb *done_ccb)
 {
-	struct scsi_mode_header_6 *mode_hdr6;
-	struct scsi_mode_header_10 *mode_hdr10;
 	struct da_softc *softc;
 	struct ccb_scsiio *csio;
 	u_int32_t  priority;
-	uint8_t dev_spec;
 
 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("dadone_probewp\n"));
 
@@ -4695,18 +4696,31 @@ dadone_probewp(struct cam_periph *periph, union ccb *done_ccb)
 		(unsigned long)csio->ccb_h.ccb_state & DA_CCB_TYPE_MASK, periph,
 		done_ccb));
 
-	if (softc->minimum_cmd_size > 6) {
-		mode_hdr10 = (struct scsi_mode_header_10 *)csio->data_ptr;
-		dev_spec = mode_hdr10->dev_spec;
-	} else {
-		mode_hdr6 = (struct scsi_mode_header_6 *)csio->data_ptr;
-		dev_spec = mode_hdr6->dev_spec;
-	}
 	if (cam_ccb_status(done_ccb) == CAM_REQ_CMP) {
+		int len, off;
+		uint8_t dev_spec;
+
+		if (csio->cdb_len > 6) {
+			struct scsi_mode_header_10 *mh =
+			    (struct scsi_mode_header_10 *)csio->data_ptr;
+			len = 2 + scsi_2btoul(mh->data_length);
+			off = sizeof(*mh) + scsi_2btoul(mh->blk_desc_len);
+			dev_spec = mh->dev_spec;
+		} else {
+			struct scsi_mode_header_6 *mh =
+			    (struct scsi_mode_header_6 *)csio->data_ptr;
+			len = 1 + mh->data_length;
+			off = sizeof(*mh) + mh->blk_desc_len;
+			dev_spec = mh->dev_spec;
+		}
 		if ((dev_spec & 0x80) != 0)
 			softc->disk->d_flags |= DISKFLAG_WRITE_PROTECT;
 		else
 			softc->disk->d_flags &= ~DISKFLAG_WRITE_PROTECT;
+
+		/* Next time request only the first of returned mode pages. */
+		if (off < len && off < csio->dxfer_len - csio->resid)
+			softc->mode_page = csio->data_ptr[off] & SMPH_PC_MASK;
 	} else {
 		int error;
 
@@ -4723,6 +4737,9 @@ dadone_probewp(struct cam_periph *periph, union ccb *done_ccb)
 						 /*timeout*/0,
 						 /*getcount_only*/0);
 			}
+
+			/* We don't depend on it, so don't try again. */
+			softc->mode_page = -1;
 		}
 	}