svn commit: r350733 - stable/12/sys/cam/ata

Alexander Motin mav at FreeBSD.org
Thu Aug 8 02:28:32 UTC 2019


Author: mav
Date: Thu Aug  8 02:28:32 2019
New Revision: 350733
URL: https://svnweb.freebsd.org/changeset/base/350733

Log:
  MFC r350233: Make CAM ATA stack handle disk resizes.
  
  While for ATA disks resize is even more rare situation than for SCSI, it
  may happen in case of HPA or AMA being used.  Make ATA XPT report minor
  IDENTIFY DATA change to upper layers with AC_GETDEV_CHANGED, and ada(4)
  periph driver handle that event, recalculating all the disk properties and
  signalling resize to GEOM.  Since ATA has no mechanism of UNIT ATTENTIONs,
  like SCSI, it has no way to detect that something has changed.  That is why
  this functionality depends on explicit reprobe via XPT_REPROBE_LUN call.

Modified:
  stable/12/sys/cam/ata/ata_da.c
  stable/12/sys/cam/ata/ata_xpt.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/cam/ata/ata_da.c
==============================================================================
--- stable/12/sys/cam/ata/ata_da.c	Thu Aug  8 02:26:12 2019	(r350732)
+++ stable/12/sys/cam/ata/ata_da.c	Thu Aug  8 02:28:32 2019	(r350733)
@@ -248,8 +248,9 @@ struct ada_softc {
 	int      periodic_read_error;
 	int      periodic_read_count;
 #endif
-	struct	 disk_params params;
-	struct	 disk *disk;
+	struct ccb_pathinq	cpi;
+	struct disk_params	params;
+	struct disk		*disk;
 	struct task		sysctl_task;
 	struct sysctl_ctx_list	sysctl_ctx;
 	struct sysctl_oid	*sysctl_tree;
@@ -804,6 +805,8 @@ static	void		adasysctlinit(void *context, int pending)
 static	int		adagetattr(struct bio *bp);
 static	void		adasetflags(struct ada_softc *softc,
 				    struct ccb_getdev *cgd);
+static void		adasetgeom(struct ada_softc *softc,
+				   struct ccb_getdev *cgd);
 static	periph_ctor_t	adaregister;
 static	void		ada_dsmtrim(struct ada_softc *softc, struct bio *bp,
 				    struct ccb_ataio *ataio);
@@ -819,8 +822,6 @@ static	void		adadone(struct cam_periph *periph,
 			       union ccb *done_ccb);
 static  int		adaerror(union ccb *ccb, u_int32_t cam_flags,
 				u_int32_t sense_flags);
-static void		adagetparams(struct cam_periph *periph,
-				struct ccb_getdev *cgd);
 static timeout_t	adasendorderedtag;
 static void		adashutdown(void *arg, int howto);
 static void		adasuspend(void *arg);
@@ -1304,9 +1305,11 @@ adaasync(void *callback_arg, u_int32_t code,
 		xpt_action((union ccb *)&cgd);
 
 		/*
-		 * Set/clear support flags based on the new Identify data.
+		 * Update our information based on the new Identify data.
 		 */
 		adasetflags(softc, &cgd);
+		adasetgeom(softc, &cgd);
+		disk_resize(softc->disk, M_NOWAIT);
 
 		cam_periph_async(periph, code, path, arg);
 		break;
@@ -1630,7 +1633,8 @@ adasetflags(struct ada_softc *softc, struct ccb_getdev
 		softc->flags &= ~ADA_FLAG_CAN_NCQ;
 
 	if ((cgd->ident_data.support_dsm & ATA_SUPPORT_DSM_TRIM) &&
-	    (cgd->inq_flags & SID_DMA)) {
+	    (cgd->inq_flags & SID_DMA) &&
+	    (softc->quirks & ADA_Q_NO_TRIM) == 0) {
 		softc->flags |= ADA_FLAG_CAN_TRIM;
 		softc->trim_max_ranges = TRIM_MAX_RANGES;
 		if (cgd->ident_data.max_dsm_blocks != 0) {
@@ -1698,13 +1702,11 @@ static cam_status
 adaregister(struct cam_periph *periph, void *arg)
 {
 	struct ada_softc *softc;
-	struct ccb_pathinq cpi;
 	struct ccb_getdev *cgd;
 	struct disk_params *dp;
 	struct sbuf sb;
 	char   *announce_buf;
 	caddr_t match;
-	u_int maxio;
 	int quirks;
 
 	cgd = (struct ccb_getdev *)arg;
@@ -1733,6 +1735,7 @@ adaregister(struct cam_periph *periph, void *arg)
 	}
 
 	periph->softc = softc;
+	xpt_path_inq(&softc->cpi, periph->path);
 
 	/*
 	 * See if this device has any quirks.
@@ -1746,8 +1749,6 @@ adaregister(struct cam_periph *periph, void *arg)
 	else
 		softc->quirks = ADA_Q_NONE;
 
-	xpt_path_inq(&cpi, periph->path);
-
 	TASK_INIT(&softc->sysctl_task, 0, adasysctlinit, periph);
 
 	/*
@@ -1773,6 +1774,8 @@ adaregister(struct cam_periph *periph, void *arg)
 	 * Set support flags based on the Identify data and quirks.
 	 */
 	adasetflags(softc, cgd);
+	if (softc->cpi.hba_misc & PIM_ATA_EXT)
+		softc->flags |= ADA_FLAG_PIM_ATA_EXT;
 
 	/* Disable queue sorting for non-rotational media by default. */
 	if (cgd->ident_data.media_rotation_rate == ATA_RATE_NON_ROTATING) {
@@ -1781,14 +1784,13 @@ adaregister(struct cam_periph *periph, void *arg)
 		softc->rotating = 1;
 	}
 	cam_iosched_set_sort_queue(softc->cam_iosched,  softc->rotating ? -1 : 0);
-	adagetparams(periph, cgd);
 	softc->disk = disk_alloc();
-	softc->disk->d_rotation_rate = cgd->ident_data.media_rotation_rate;
+	adasetgeom(softc, cgd);
 	softc->disk->d_devstat = devstat_new_entry(periph->periph_name,
 			  periph->unit_number, softc->params.secsize,
 			  DEVSTAT_ALL_SUPPORTED,
 			  DEVSTAT_TYPE_DIRECT |
-			  XPORT_DEVSTAT_TYPE(cpi.transport),
+			  XPORT_DEVSTAT_TYPE(softc->cpi.transport),
 			  DEVSTAT_PRIORITY_DISK);
 	softc->disk->d_open = adaopen;
 	softc->disk->d_close = adaclose;
@@ -1798,70 +1800,8 @@ adaregister(struct cam_periph *periph, void *arg)
 	softc->disk->d_gone = adadiskgonecb;
 	softc->disk->d_name = "ada";
 	softc->disk->d_drv1 = periph;
-	maxio = cpi.maxio;		/* Honor max I/O size of SIM */
-	if (maxio == 0)
-		maxio = DFLTPHYS;	/* traditional default */
-	else if (maxio > MAXPHYS)
-		maxio = MAXPHYS;	/* for safety */
-	if (softc->flags & ADA_FLAG_CAN_48BIT)
-		maxio = min(maxio, 65536 * softc->params.secsize);
-	else					/* 28bit ATA command limit */
-		maxio = min(maxio, 256 * softc->params.secsize);
-	if (softc->quirks & ADA_Q_128KB)
-		maxio = min(maxio, 128 * 1024);
-	softc->disk->d_maxsize = maxio;
 	softc->disk->d_unit = periph->unit_number;
-	softc->disk->d_flags = DISKFLAG_DIRECT_COMPLETION | DISKFLAG_CANZONE;
-	if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE)
-		softc->disk->d_flags |= DISKFLAG_CANFLUSHCACHE;
-	/* Device lies about TRIM capability. */
-	if ((softc->quirks & ADA_Q_NO_TRIM) &&
-	    (softc->flags & ADA_FLAG_CAN_TRIM))
-		softc->flags &= ~ADA_FLAG_CAN_TRIM;
-	if (softc->flags & ADA_FLAG_CAN_TRIM) {
-		softc->disk->d_flags |= DISKFLAG_CANDELETE;
-		softc->disk->d_delmaxsize = softc->params.secsize *
-					    ATA_DSM_RANGE_MAX *
-					    softc->trim_max_ranges;
-	} else if ((softc->flags & ADA_FLAG_CAN_CFA) &&
-	    !(softc->flags & ADA_FLAG_CAN_48BIT)) {
-		softc->disk->d_flags |= DISKFLAG_CANDELETE;
-		softc->disk->d_delmaxsize = 256 * softc->params.secsize;
-	} else
-		softc->disk->d_delmaxsize = maxio;
-	if ((cpi.hba_misc & PIM_UNMAPPED) != 0) {
-		softc->disk->d_flags |= DISKFLAG_UNMAPPED_BIO;
-		softc->unmappedio = 1;
-	}
-	if (cpi.hba_misc & PIM_ATA_EXT)
-		softc->flags |= ADA_FLAG_PIM_ATA_EXT;
-	strlcpy(softc->disk->d_descr, cgd->ident_data.model,
-	    MIN(sizeof(softc->disk->d_descr), sizeof(cgd->ident_data.model)));
-	strlcpy(softc->disk->d_ident, cgd->ident_data.serial,
-	    MIN(sizeof(softc->disk->d_ident), sizeof(cgd->ident_data.serial)));
-	softc->disk->d_hba_vendor = cpi.hba_vendor;
-	softc->disk->d_hba_device = cpi.hba_device;
-	softc->disk->d_hba_subvendor = cpi.hba_subvendor;
-	softc->disk->d_hba_subdevice = cpi.hba_subdevice;
 
-	softc->disk->d_sectorsize = softc->params.secsize;
-	softc->disk->d_mediasize = (off_t)softc->params.sectors *
-	    softc->params.secsize;
-	if (ata_physical_sector_size(&cgd->ident_data) !=
-	    softc->params.secsize) {
-		softc->disk->d_stripesize =
-		    ata_physical_sector_size(&cgd->ident_data);
-		softc->disk->d_stripeoffset = (softc->disk->d_stripesize -
-		    ata_logical_sector_offset(&cgd->ident_data)) %
-		    softc->disk->d_stripesize;
-	} else if (softc->quirks & ADA_Q_4K) {
-		softc->disk->d_stripesize = 4096;
-		softc->disk->d_stripeoffset = 0;
-	}
-	softc->disk->d_fwsectors = softc->params.secs_per_track;
-	softc->disk->d_fwheads = softc->params.heads;
-	ata_disk_firmware_geom_adjust(softc->disk);
-
 	/*
 	 * Acquire a reference to the periph before we register with GEOM.
 	 * We'll release this reference once GEOM calls us back (via
@@ -3368,16 +3308,17 @@ adaerror(union ccb *ccb, u_int32_t cam_flags, u_int32_
 }
 
 static void
-adagetparams(struct cam_periph *periph, struct ccb_getdev *cgd)
+adasetgeom(struct ada_softc *softc, struct ccb_getdev *cgd)
 {
-	struct ada_softc *softc = (struct ada_softc *)periph->softc;
 	struct disk_params *dp = &softc->params;
 	u_int64_t lbasize48;
 	u_int32_t lbasize;
+	u_int maxio, d_flags;
 
 	dp->secsize = ata_logical_sector_size(&cgd->ident_data);
 	if ((cgd->ident_data.atavalid & ATA_FLAG_54_58) &&
-		cgd->ident_data.current_heads && cgd->ident_data.current_sectors) {
+	    cgd->ident_data.current_heads != 0 &&
+	    cgd->ident_data.current_sectors != 0) {
 		dp->heads = cgd->ident_data.current_heads;
 		dp->secs_per_track = cgd->ident_data.current_sectors;
 		dp->cylinders = cgd->ident_data.cylinders;
@@ -3405,6 +3346,60 @@ adagetparams(struct cam_periph *periph, struct ccb_get
 	if ((cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) &&
 	    lbasize48 > ATA_MAX_28BIT_LBA)
 		dp->sectors = lbasize48;
+
+	maxio = softc->cpi.maxio;		/* Honor max I/O size of SIM */
+	if (maxio == 0)
+		maxio = DFLTPHYS;	/* traditional default */
+	else if (maxio > MAXPHYS)
+		maxio = MAXPHYS;	/* for safety */
+	if (softc->flags & ADA_FLAG_CAN_48BIT)
+		maxio = min(maxio, 65536 * softc->params.secsize);
+	else					/* 28bit ATA command limit */
+		maxio = min(maxio, 256 * softc->params.secsize);
+	if (softc->quirks & ADA_Q_128KB)
+		maxio = min(maxio, 128 * 1024);
+	softc->disk->d_maxsize = maxio;
+	d_flags = DISKFLAG_DIRECT_COMPLETION | DISKFLAG_CANZONE;
+	if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE)
+		d_flags |= DISKFLAG_CANFLUSHCACHE;
+	if (softc->flags & ADA_FLAG_CAN_TRIM) {
+		d_flags |= DISKFLAG_CANDELETE;
+		softc->disk->d_delmaxsize = softc->params.secsize *
+		    ATA_DSM_RANGE_MAX * softc->trim_max_ranges;
+	} else if ((softc->flags & ADA_FLAG_CAN_CFA) &&
+	    !(softc->flags & ADA_FLAG_CAN_48BIT)) {
+		d_flags |= DISKFLAG_CANDELETE;
+		softc->disk->d_delmaxsize = 256 * softc->params.secsize;
+	} else
+		softc->disk->d_delmaxsize = maxio;
+	if ((softc->cpi.hba_misc & PIM_UNMAPPED) != 0) {
+		d_flags |= DISKFLAG_UNMAPPED_BIO;
+		softc->unmappedio = 1;
+	}
+	softc->disk->d_flags = d_flags;
+	strlcpy(softc->disk->d_descr, cgd->ident_data.model,
+	    MIN(sizeof(softc->disk->d_descr), sizeof(cgd->ident_data.model)));
+	strlcpy(softc->disk->d_ident, cgd->ident_data.serial,
+	    MIN(sizeof(softc->disk->d_ident), sizeof(cgd->ident_data.serial)));
+
+	softc->disk->d_sectorsize = softc->params.secsize;
+	softc->disk->d_mediasize = (off_t)softc->params.sectors *
+	    softc->params.secsize;
+	if (ata_physical_sector_size(&cgd->ident_data) !=
+	    softc->params.secsize) {
+		softc->disk->d_stripesize =
+		    ata_physical_sector_size(&cgd->ident_data);
+		softc->disk->d_stripeoffset = (softc->disk->d_stripesize -
+		    ata_logical_sector_offset(&cgd->ident_data)) %
+		    softc->disk->d_stripesize;
+	} else if (softc->quirks & ADA_Q_4K) {
+		softc->disk->d_stripesize = 4096;
+		softc->disk->d_stripeoffset = 0;
+	}
+	softc->disk->d_fwsectors = softc->params.secs_per_track;
+	softc->disk->d_fwheads = softc->params.heads;
+	ata_disk_firmware_geom_adjust(softc->disk);
+	softc->disk->d_rotation_rate = cgd->ident_data.media_rotation_rate;
 }
 
 static void

Modified: stable/12/sys/cam/ata/ata_xpt.c
==============================================================================
--- stable/12/sys/cam/ata/ata_xpt.c	Thu Aug  8 02:26:12 2019	(r350732)
+++ stable/12/sys/cam/ata/ata_xpt.c	Thu Aug  8 02:28:32 2019	(r350733)
@@ -344,6 +344,7 @@ probestart(struct cam_periph *periph, union ccb *start
 	probe_softc *softc;
 	struct cam_path *path;
 	struct ata_params *ident_buf;
+	u_int oif;
 
 	CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probestart\n"));
 
@@ -383,7 +384,7 @@ probestart(struct cam_periph *periph, union ccb *start
 		      /*data_ptr*/(u_int8_t *)&softc->ident_data,
 		      /*dxfer_len*/sizeof(softc->ident_data),
 		      30 * 1000);
-		if (periph->path->device->protocol == PROTO_ATA)
+		if (path->device->protocol == PROTO_ATA)
 			ata_28bit_cmd(ataio, ATA_ATA_IDENTIFY, 0, 0, 0);
 		else
 			ata_28bit_cmd(ataio, ATA_ATAPI_IDENTIFY, 0, 0, 0);
@@ -419,7 +420,7 @@ probestart(struct cam_periph *periph, union ccb *start
 			if (cts.xport_specific.sata.valid & CTS_SATA_VALID_MODE)
 				mode = cts.xport_specific.sata.mode;
 		}
-		if (periph->path->device->protocol == PROTO_ATA) {
+		if (path->device->protocol == PROTO_ATA) {
 			if (ata_dma == 0 && (mode == 0 || mode > ATA_PIO_MAX))
 				mode = ATA_PIO_MAX;
 		} else {
@@ -459,11 +460,13 @@ negotiate:
 		if (mode != wantmode)
 			goto negotiate;
 		/* Remember what transport thinks about DMA. */
+		oif = path->device->inq_flags;
 		if (mode < ATA_DMA)
 			path->device->inq_flags &= ~SID_DMA;
 		else
 			path->device->inq_flags |= SID_DMA;
-		xpt_async(AC_GETDEV_CHANGED, path, NULL);
+		if (path->device->inq_flags != oif)
+			xpt_async(AC_GETDEV_CHANGED, path, NULL);
 		cam_fill_ataio(ataio,
 		      1,
 		      probedone,
@@ -516,11 +519,13 @@ negotiate:
 		break;
 	case PROBE_SETAN:
 		/* Remember what transport thinks about AEN. */
+		oif = path->device->inq_flags;
 		if (softc->caps & CTS_SATA_CAPS_H_AN)
 			path->device->inq_flags |= SID_AEN;
 		else
 			path->device->inq_flags &= ~SID_AEN;
-		xpt_async(AC_GETDEV_CHANGED, path, NULL);
+		if (path->device->inq_flags != oif)
+			xpt_async(AC_GETDEV_CHANGED, path, NULL);
 		cam_fill_ataio(ataio,
 		    1,
 		    probedone,
@@ -639,7 +644,7 @@ negotiate:
 	{
 		u_int inquiry_len;
 		struct scsi_inquiry_data *inq_buf =
-		    &periph->path->device->inq_data;
+		    &path->device->inq_data;
 
 		if (softc->action == PROBE_INQUIRY)
 			inquiry_len = SHORT_INQUIRY_LENGTH;
@@ -744,8 +749,8 @@ probedone(struct cam_periph *periph, union ccb *done_c
 	struct cam_path *path;
 	cam_status status;
 	u_int32_t  priority;
-	u_int caps;
-	int changed = 1, found = 1;
+	u_int caps, oif;
+	int changed, found = 1;
 	static const uint8_t fake_device_id_hdr[8] =
 	    {0, SVPD_DEVICE_ID, 0, 12,
 	     SVPD_ID_CODESET_BINARY, SVPD_ID_TYPE_NAA, 0, 8};
@@ -922,23 +927,32 @@ noerror:
 			goto out;
 		}
 		ident_buf = &path->device->ident_data;
+
+		/* Check that it is the same device as we know. */
 		if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) {
-			/* Check that it is the same device. */
 			if (bcmp(softc->ident_data.model, ident_buf->model,
 			     sizeof(ident_buf->model)) ||
-			    bcmp(softc->ident_data.revision, ident_buf->revision,
-			     sizeof(ident_buf->revision)) ||
 			    bcmp(softc->ident_data.serial, ident_buf->serial,
 			     sizeof(ident_buf->serial))) {
-				/* Device changed. */
+				/* The device was replaced. */
+				changed = 2;
 				xpt_async(AC_LOST_DEVICE, path, NULL);
+			} else if (bcmp(&softc->ident_data, ident_buf,
+			     sizeof(*ident_buf))) {
+				/* The device is the same, but has changed. */
+				changed = 1;
 			} else {
-				bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params));
+				/* Nothing has changed. */
 				changed = 0;
 			}
+		} else {
+			/* This is a new device. */
+			changed = 2;
 		}
-		if (changed) {
+
+		if (changed != 0)
 			bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params));
+		if (changed == 2) {
 			/* Clean up from previous instance of this device */
 			if (path->device->serial_num != NULL) {
 				free(path->device->serial_num, M_CAMXPT);
@@ -975,10 +989,10 @@ noerror:
 					ata_bswap(path->device->device_id + 8, 8);
 				}
 			}
-
 			path->device->flags |= CAM_DEV_IDENTIFY_DATA_VALID;
-			xpt_async(AC_GETDEV_CHANGED, path, NULL);
 		}
+		if (changed == 1)
+			xpt_async(AC_GETDEV_CHANGED, path, NULL);
 		if (ident_buf->satacapabilities & ATA_SUPPORT_NCQ) {
 			path->device->mintags = 2;
 			path->device->maxtags =
@@ -1002,7 +1016,7 @@ noerror:
 			}
 		}
 		ata_device_transport(path);
-		if (changed)
+		if (changed == 2)
 			proberequestdefaultnegotiation(periph);
 		PROBE_SET_ACTION(softc, PROBE_SETMODE);
 		xpt_release_ccb(done_ccb);
@@ -1058,6 +1072,7 @@ noerror:
 		 * capability information is not provided or transport is
 		 * SATA, we take support for granted.
 		 */
+		oif = path->device->inq_flags;
 		if (!(path->device->inq_flags & SID_DMA) ||
 		    (path->device->transport == XPORT_ATA &&
 		    (cts.xport_specific.ata.valid & CTS_ATA_VALID_CAPS) &&
@@ -1065,6 +1080,8 @@ noerror:
 			path->device->inq_flags &= ~SID_DMA48;
 		else
 			path->device->inq_flags |= SID_DMA48;
+		if (path->device->inq_flags != oif)
+			xpt_async(AC_GETDEV_CHANGED, path, NULL);
 		/* Store result to SIM. */
 		bzero(&cts, sizeof(cts));
 		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
@@ -1235,6 +1252,7 @@ notsata:
 		else
 			caps = 0;
 		/* Remember what transport thinks about AEN. */
+		oif = path->device->inq_flags;
 		if ((caps & CTS_SATA_CAPS_H_AN) && path->device->protocol != PROTO_ATA)
 			path->device->inq_flags |= SID_AEN;
 		else
@@ -1248,7 +1266,6 @@ notsata:
 		cts.xport_specific.sata.valid = CTS_SATA_VALID_CAPS;
 		xpt_action((union ccb *)&cts);
 		softc->caps = caps;
-		xpt_async(AC_GETDEV_CHANGED, path, NULL);
 		if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
 			path->device->flags &= ~CAM_DEV_UNCONFIGURED;
 			xpt_acquire_device(path->device);
@@ -1256,6 +1273,8 @@ notsata:
 			xpt_action(done_ccb);
 			xpt_async(AC_FOUND_DEVICE, path, done_ccb);
 		} else {
+			if (path->device->inq_flags != oif)
+				xpt_async(AC_GETDEV_CHANGED, path, NULL);
 			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
 			xpt_action(done_ccb);
 			xpt_async(AC_SCSI_AEN, path, done_ccb);
@@ -1268,12 +1287,14 @@ notsata:
 			/* Check that it is the same device. */
 			if (bcmp(&softc->ident_data, ident_buf, 53)) {
 				/* Device changed. */
+				changed = 2;
 				xpt_async(AC_LOST_DEVICE, path, NULL);
 			} else {
 				bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params));
 				changed = 0;
 			}
-		}
+		} else
+			changed = 2;
 		if (changed) {
 			bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params));
 			/* Clean up from previous instance of this device */


More information about the svn-src-all mailing list