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_ */
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-stable-9
To unsubscribe, send any mail to "[email protected]"

Reply via email to