svn commit: r252730 - in stable/9/sys: cam/ata cam/scsi geom

Steven Hartland smh at FreeBSD.org
Thu Jul 4 21:57:10 UTC 2013


Author: smh
Date: Thu Jul  4 21:57:09 2013
New Revision: 252730
URL: http://svnweb.freebsd.org/changeset/base/252730

Log:
  MFC r249940:
  Teach GEOM and CAM about the difference between the max "size" of r/w and delete
  requests.
  
  MFC r252657:
  Bump disk(9) ABI version to signify the addition of d_delmaxsize.
  
  Make the addition of the d_delmaxsize binary compatible.  This allows storage
  drivers compiled for 9.0 and 9.1 to work by preserving the ABI for disks.
  
  Reviewed by:	mav

Modified:
  stable/9/sys/cam/ata/ata_da.c
  stable/9/sys/cam/scsi/scsi_da.c
  stable/9/sys/geom/geom_disk.c
  stable/9/sys/geom/geom_disk.h
Directory Properties:
  stable/9/sys/   (props changed)

Modified: stable/9/sys/cam/ata/ata_da.c
==============================================================================
--- stable/9/sys/cam/ata/ata_da.c	Thu Jul  4 21:31:28 2013	(r252729)
+++ stable/9/sys/cam/ata/ata_da.c	Thu Jul  4 21:57:09 2013	(r252730)
@@ -1239,10 +1239,15 @@ adaregister(struct cam_periph *periph, v
 		softc->disk->d_flags |= DISKFLAG_CANFLUSHCACHE;
 	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;
 	strlcpy(softc->disk->d_descr, cgd->ident_data.model,

Modified: stable/9/sys/cam/scsi/scsi_da.c
==============================================================================
--- stable/9/sys/cam/scsi/scsi_da.c	Thu Jul  4 21:31:28 2013	(r252729)
+++ stable/9/sys/cam/scsi/scsi_da.c	Thu Jul  4 21:57:09 2013	(r252730)
@@ -1064,8 +1064,11 @@ static	void		daasync(void *callback_arg,
 static	void		dasysctlinit(void *context, int pending);
 static	int		dacmdsizesysctl(SYSCTL_HANDLER_ARGS);
 static	int		dadeletemethodsysctl(SYSCTL_HANDLER_ARGS);
+static	int		dadeletemaxsysctl(SYSCTL_HANDLER_ARGS);
 static	void		dadeletemethodset(struct da_softc *softc,
 					  da_delete_methods delete_method);
+static	off_t		dadeletemaxsize(struct da_softc *softc,
+					da_delete_methods delete_method);
 static	void		dadeletemethodchoose(struct da_softc *softc,
 					     da_delete_methods default_method);
 static	void		daprobedone(struct cam_periph *periph, union ccb *ccb);
@@ -1692,6 +1695,10 @@ dasysctlinit(void *context, int pending)
 		softc, 0, dadeletemethodsysctl, "A",
 		"BIO_DELETE execution method");
 	SYSCTL_ADD_PROC(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree),
+		OID_AUTO, "delete_max", CTLTYPE_U64 | CTLFLAG_RW,
+		softc, 0, dadeletemaxsysctl, "Q",
+		"Maximum BIO_DELETE size");
+	SYSCTL_ADD_PROC(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree),
 		OID_AUTO, "minimum_cmd_size", CTLTYPE_INT | CTLFLAG_RW,
 		&softc->minimum_cmd_size, 0, dacmdsizesysctl, "I",
 		"Minimum CDB size");
@@ -1737,6 +1744,29 @@ dasysctlinit(void *context, int pending)
 }
 
 static int
+dadeletemaxsysctl(SYSCTL_HANDLER_ARGS)
+{
+	int error;
+	uint64_t value;
+	struct da_softc *softc;
+
+	softc = (struct da_softc *)arg1;
+
+	value = softc->disk->d_delmaxsize;
+	error = sysctl_handle_64(oidp, &value, 0, req);
+	if ((error != 0) || (req->newptr == NULL))
+		return (error);
+
+	/* only accept values smaller than the calculated value */
+	if (value > dadeletemaxsize(softc, softc->delete_method)) {
+		return (EINVAL);
+	}
+	softc->disk->d_delmaxsize = value;
+
+	return (0);
+}
+
+static int
 dacmdsizesysctl(SYSCTL_HANDLER_ARGS)
 {
 	int error, value;
@@ -1774,6 +1804,7 @@ dadeletemethodset(struct da_softc *softc
 
 
 	softc->delete_method = delete_method;
+	softc->disk->d_delmaxsize = dadeletemaxsize(softc, delete_method);
 
 	if (softc->delete_method > DA_DELETE_DISABLE)
 		softc->disk->d_flags |= DISKFLAG_CANDELETE;
@@ -1781,6 +1812,33 @@ dadeletemethodset(struct da_softc *softc
 		softc->disk->d_flags &= ~DISKFLAG_CANDELETE;
 }
 
+static off_t
+dadeletemaxsize(struct da_softc *softc, da_delete_methods delete_method)
+{
+	off_t sectors;
+
+	switch(delete_method) {
+	case DA_DELETE_UNMAP:
+		sectors = (off_t)softc->unmap_max_lba * softc->unmap_max_ranges;
+		break;
+	case DA_DELETE_ATA_TRIM:
+		sectors = (off_t)ATA_DSM_RANGE_MAX * softc->trim_max_ranges;
+		break;
+	case DA_DELETE_WS16:
+		sectors = (off_t)min(softc->ws_max_blks, WS16_MAX_BLKS);
+		break;
+	case DA_DELETE_ZERO:
+	case DA_DELETE_WS10:
+		sectors = (off_t)min(softc->ws_max_blks, WS10_MAX_BLKS);
+		break;
+	default:
+		return 0;
+	}
+
+	return (off_t)softc->params.secsize *
+	    min(sectors, (off_t)softc->params.sectors);
+}
+
 static void
 daprobedone(struct cam_periph *periph, union ccb *ccb)
 {
@@ -2304,8 +2362,13 @@ skipstate:
 		    } else if (softc->delete_method == DA_DELETE_ZERO ||
 			       softc->delete_method == DA_DELETE_WS10 ||
 			       softc->delete_method == DA_DELETE_WS16) {
+			/*
+			 * We calculate ws_max_blks here based off d_delmaxsize instead
+			 * of using softc->ws_max_blks as it is absolute max for the
+			 * device not the protocol max which may well be lower
+			 */
 			uint64_t ws_max_blks;
-			ws_max_blks = softc->ws_max_blks / softc->params.secsize;
+			ws_max_blks = softc->disk->d_delmaxsize / softc->params.secsize;
 			softc->delete_running = 1;
 			lba = bp->bio_pblkno;
 			count = 0;

Modified: stable/9/sys/geom/geom_disk.c
==============================================================================
--- stable/9/sys/geom/geom_disk.c	Thu Jul  4 21:31:28 2013	(r252729)
+++ stable/9/sys/geom/geom_disk.c	Thu Jul  4 21:57:09 2013	(r252730)
@@ -155,6 +155,13 @@ g_disk_access(struct g_provider *pp, int
 			    dp->d_name, dp->d_unit);
 			dp->d_maxsize = DFLTPHYS;
 		}
+		if (dp->d_delmaxsize == 0) {
+			if (bootverbose && dp->d_flags & DISKFLAG_CANDELETE) {
+				printf("WARNING: Disk drive %s%d has no "
+				    "d_delmaxsize\n", dp->d_name, dp->d_unit);
+			}
+			dp->d_delmaxsize = dp->d_maxsize;
+		}
 	} else if ((pp->acr + pp->acw + pp->ace) > 0 && (r + w + e) == 0) {
 		if (dp->d_close != NULL) {
 			g_disk_lock_giant(dp);
@@ -299,6 +306,12 @@ g_disk_start(struct bio *bp)
 			break;
 		}
 		do {
+			off_t d_maxsize;
+
+			d_maxsize = (bp->bio_cmd == BIO_DELETE &&
+			    (dp->d_flags & DISKFLAG_LACKS_DELMAX) == 0) ?
+			    dp->d_delmaxsize : dp->d_maxsize;
+
 			bp2->bio_offset += off;
 			bp2->bio_length -= off;
 			if ((bp->bio_flags & BIO_UNMAPPED) == 0) {
@@ -313,18 +326,20 @@ g_disk_start(struct bio *bp)
 				bp2->bio_ma_offset %= PAGE_SIZE;
 				bp2->bio_ma_n -= off / PAGE_SIZE;
 			}
-			if (bp2->bio_length > dp->d_maxsize) {
+			if (bp2->bio_length > d_maxsize) {
 				/*
 				 * XXX: If we have a stripesize we should really
-				 * use it here.
+				 * use it here. Care should be taken in the delete
+				 * case if this is done as deletes can be very 
+				 * sensitive to size given how they are processed.
 				 */
-				bp2->bio_length = dp->d_maxsize;
+				bp2->bio_length = d_maxsize;
 				if ((bp->bio_flags & BIO_UNMAPPED) != 0) {
 					bp2->bio_ma_n = howmany(
 					    bp2->bio_ma_offset +
 					    bp2->bio_length, PAGE_SIZE);
 				}
-				off += dp->d_maxsize;
+				off += d_maxsize;
 				/*
 				 * To avoid a race, we need to grab the next bio
 				 * before we schedule this one.  See "notes".
@@ -603,7 +618,8 @@ void
 disk_create(struct disk *dp, int version)
 {
 
-	if (version != DISK_VERSION_02 && version != DISK_VERSION_01) {
+	if (version != DISK_VERSION_03 && version != DISK_VERSION_02 &&
+	    version != DISK_VERSION_01) {
 		printf("WARNING: Attempt to add disk %s%d %s",
 		    dp->d_name, dp->d_unit,
 		    " using incompatible ABI version of disk(9)\n");
@@ -613,6 +629,8 @@ disk_create(struct disk *dp, int version
 	}
 	if (version == DISK_VERSION_01)
 		dp->d_flags |= DISKFLAG_LACKS_GONE;
+	if (version < DISK_VERSION_03)
+		dp->d_flags |= DISKFLAG_LACKS_DELMAX;
 	KASSERT(dp->d_strategy != NULL, ("disk_create need d_strategy"));
 	KASSERT(dp->d_name != NULL, ("disk_create need d_name"));
 	KASSERT(*dp->d_name != 0, ("disk_create need d_name"));

Modified: stable/9/sys/geom/geom_disk.h
==============================================================================
--- stable/9/sys/geom/geom_disk.h	Thu Jul  4 21:31:28 2013	(r252729)
+++ stable/9/sys/geom/geom_disk.h	Thu Jul  4 21:57:09 2013	(r252730)
@@ -99,6 +99,9 @@ struct disk {
 
 	/* new fields in stable - don't use if DISKFLAG_LACKS_GONE is set */
 	disk_gone_t		*d_gone;
+
+	/* new fields in stable - don't use if DISKFLAG_LACKS_DELMAX is set */
+	off_t			d_delmaxsize;
 };
 
 #define DISKFLAG_NEEDSGIANT	0x1
@@ -106,7 +109,8 @@ struct disk {
 #define DISKFLAG_CANDELETE	0x4
 #define DISKFLAG_CANFLUSHCACHE	0x8
 #define DISKFLAG_LACKS_GONE	0x10
-#define	DISKFLAG_UNMAPPED_BIO	0x20
+#define DISKFLAG_UNMAPPED_BIO	0x20
+#define DISKFLAG_LACKS_DELMAX	0x40
 
 struct disk *disk_alloc(void);
 void disk_create(struct disk *disk, int version);
@@ -119,7 +123,8 @@ void disk_media_gone(struct disk *dp, in
 #define DISK_VERSION_00		0x58561059
 #define DISK_VERSION_01		0x5856105a
 #define DISK_VERSION_02		0x5856105b
-#define DISK_VERSION		DISK_VERSION_02
+#define DISK_VERSION_03		0x5856105c
+#define DISK_VERSION		DISK_VERSION_03
 
 #endif /* _KERNEL */
 #endif /* _GEOM_GEOM_DISK_H_ */


More information about the svn-src-all mailing list