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 */
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to