Author: mav
Date: Thu Feb 21 18:15:41 2013
New Revision: 247111
URL: http://svnweb.freebsd.org/changeset/base/247111

Log:
  MFC r230590 (by ken) except parts changing ABI:
  Add CAM infrastructure to allow reporting when a drive's long read capacity
  data changes.

Modified:
  stable/9/sys/cam/cam_ccb.h
  stable/9/sys/cam/cam_xpt.c
  stable/9/sys/cam/cam_xpt_internal.h
  stable/9/sys/cam/scsi/scsi_all.h
  stable/9/sys/cam/scsi/scsi_da.c
  stable/9/sys/cam/scsi/scsi_xpt.c
Directory Properties:
  stable/9/sys/   (props changed)
  stable/9/sys/amd64/include/xen/   (props changed)
  stable/9/sys/boot/   (props changed)
  stable/9/sys/boot/i386/efi/   (props changed)
  stable/9/sys/boot/ia64/efi/   (props changed)
  stable/9/sys/boot/ia64/ski/   (props changed)
  stable/9/sys/boot/powerpc/boot1.chrp/   (props changed)
  stable/9/sys/boot/powerpc/ofw/   (props changed)
  stable/9/sys/cddl/contrib/opensolaris/   (props changed)
  stable/9/sys/conf/   (props changed)
  stable/9/sys/contrib/dev/acpica/   (props changed)
  stable/9/sys/contrib/octeon-sdk/   (props changed)
  stable/9/sys/contrib/pf/   (props changed)
  stable/9/sys/contrib/x86emu/   (props changed)
  stable/9/sys/dev/   (props changed)
  stable/9/sys/dev/e1000/   (props changed)
  stable/9/sys/dev/isp/   (props changed)
  stable/9/sys/dev/ixgbe/   (props changed)
  stable/9/sys/dev/puc/   (props changed)
  stable/9/sys/fs/   (props changed)
  stable/9/sys/fs/ntfs/   (props changed)
  stable/9/sys/modules/   (props changed)

Modified: stable/9/sys/cam/cam_ccb.h
==============================================================================
--- stable/9/sys/cam/cam_ccb.h  Thu Feb 21 17:54:14 2013        (r247110)
+++ stable/9/sys/cam/cam_ccb.h  Thu Feb 21 18:15:41 2013        (r247111)
@@ -1128,6 +1128,7 @@ struct ccb_dev_advinfo {
 #define        CDAI_TYPE_SCSI_DEVID    1
 #define        CDAI_TYPE_SERIAL_NUM    2
 #define        CDAI_TYPE_PHYS_PATH     3
+#define        CDAI_TYPE_RCAPLONG      4
        off_t bufsiz;                   /* IN: Size of external buffer */
 #define        CAM_SCSI_DEVID_MAXLEN   65536   /* length in buffer is an 
uint16_t */
        off_t provsiz;                  /* OUT: Size required/used */

Modified: stable/9/sys/cam/cam_xpt.c
==============================================================================
--- stable/9/sys/cam/cam_xpt.c  Thu Feb 21 17:54:14 2013        (r247110)
+++ stable/9/sys/cam/cam_xpt.c  Thu Feb 21 18:15:41 2013        (r247111)
@@ -4616,6 +4616,17 @@ xpt_release_device(struct cam_ed *device
                cam_devq_resize(devq, devq->alloc_queue.array_size - 1);
                camq_fini(&device->drvq);
                cam_ccbq_fini(&device->ccbq);
+               /*
+                * Free allocated memory.  free(9) does nothing if the
+                * supplied pointer is NULL, so it is safe to call without
+                * checking.
+                */
+               free(device->supported_vpds, M_CAMXPT);
+               free(device->device_id, M_CAMXPT);
+               free(device->physpath, M_CAMXPT);
+               free(device->rcap_buf, M_CAMXPT);
+               free(device->serial_num, M_CAMXPT);
+
                xpt_release_target(device->target);
                free(device, M_CAMDEV);
        } else

Modified: stable/9/sys/cam/cam_xpt_internal.h
==============================================================================
--- stable/9/sys/cam/cam_xpt_internal.h Thu Feb 21 17:54:14 2013        
(r247110)
+++ stable/9/sys/cam/cam_xpt_internal.h Thu Feb 21 18:15:41 2013        
(r247111)
@@ -99,6 +99,8 @@ struct cam_ed {
        uint8_t          *device_id;
        uint8_t          physpath_len;
        uint8_t          *physpath;     /* physical path string form */
+       uint32_t         rcap_len;
+       uint8_t          *rcap_buf;
        struct           ata_params ident_data;
        u_int8_t         inq_flags;     /*
                                         * Current settings for inquiry flags.

Modified: stable/9/sys/cam/scsi/scsi_all.h
==============================================================================
--- stable/9/sys/cam/scsi/scsi_all.h    Thu Feb 21 17:54:14 2013        
(r247110)
+++ stable/9/sys/cam/scsi/scsi_all.h    Thu Feb 21 18:15:41 2013        
(r247111)
@@ -1444,14 +1444,24 @@ struct scsi_read_capacity_data_long
        uint8_t length[4];
 #define        SRC16_PROT_EN           0x01
 #define        SRC16_P_TYPE            0x0e
+#define        SRC16_PTYPE_1           0x00
+#define        SRC16_PTYPE_2           0x02
+#define        SRC16_PTYPE_3           0x04
        uint8_t prot;
 #define        SRC16_LBPPBE            0x0f
 #define        SRC16_PI_EXPONENT       0xf0
 #define        SRC16_PI_EXPONENT_SHIFT 4
        uint8_t prot_lbppbe;
-#define        SRC16_LALBA             0x3fff
-#define        SRC16_LBPRZ             0x4000
-#define        SRC16_LBPME             0x8000
+#define        SRC16_LALBA             0x3f
+#define        SRC16_LBPRZ             0x40
+#define        SRC16_LBPME             0x80
+/*
+ * Alternate versions of these macros that are intended for use on a 16-bit
+ * version of the lalba_lbp field instead of the array of 2 8 bit numbers.
+ */
+#define        SRC16_LALBA_A           0x3fff
+#define        SRC16_LBPRZ_A           0x4000
+#define        SRC16_LBPME_A           0x8000
        uint8_t lalba_lbp[2];
 };
 

Modified: stable/9/sys/cam/scsi/scsi_da.c
==============================================================================
--- stable/9/sys/cam/scsi/scsi_da.c     Thu Feb 21 17:54:14 2013        
(r247110)
+++ stable/9/sys/cam/scsi/scsi_da.c     Thu Feb 21 18:15:41 2013        
(r247111)
@@ -159,6 +159,7 @@ struct da_softc {
        struct callout          sendordered_c;
        uint64_t wwpn;
        uint8_t  unmap_buf[UNMAP_MAX_RANGES * 16 + 8];
+       struct scsi_read_capacity_data_long rcaplong;
 };
 
 struct da_quirk_entry {
@@ -868,7 +869,9 @@ static  int         daerror(union ccb *ccb, u_i
 static void            daprevent(struct cam_periph *periph, int action);
 static int             dagetcapacity(struct cam_periph *periph);
 static void            dasetgeom(struct cam_periph *periph, uint32_t block_len,
-                                 uint64_t maxsector, u_int lbppbe, u_int 
lalba);
+                                 uint64_t maxsector,
+                                 struct scsi_read_capacity_data_long *rcaplong,
+                                 size_t rcap_size);
 static timeout_t       dasendorderedtag;
 static void            dashutdown(void *arg, int howto);
 
@@ -2262,10 +2265,15 @@ dadone(struct cam_periph *periph, union 
                                announce_buf[0] = '\0';
                                cam_periph_invalidate(periph);
                        } else {
+                               /*
+                                * We pass rcaplong into dasetgeom(),
+                                * because it will only use it if it is
+                                * non-NULL.
+                                */
                                dasetgeom(periph, block_size, maxsector,
-                                   lbppbe, lalba & SRC16_LALBA);
-                               if ((lalba & SRC16_LBPME) &&
-                                   softc->delete_method == DA_DELETE_NONE)
+                                         rcaplong, sizeof(*rcaplong));
+                               if ((lalba & SRC16_LBPME_A)
+                                && softc->delete_method == DA_DELETE_NONE)
                                        softc->delete_method = DA_DELETE_UNMAP;
                                dp = &softc->params;
                                snprintf(announce_buf, sizeof(announce_buf),
@@ -2539,6 +2547,7 @@ dagetcapacity(struct cam_periph *periph)
        lalba = 0;
        error = 0;
        rc16failed = 0;
+       rcaplong = NULL;
        sense_flags = SF_RETRY_UA;
        if (softc->flags & DA_FLAG_PACK_REMOVABLE)
                sense_flags |= SF_NO_PRINT;
@@ -2556,39 +2565,46 @@ dagetcapacity(struct cam_periph *periph)
        /* Try READ CAPACITY(16) first if we think it should work. */
        if (softc->flags & DA_FLAG_CAN_RC16) {
                scsi_read_capacity_16(&ccb->csio,
-                             /*retries*/ 4,
-                             /*cbfcnp*/ dadone,
-                             /*tag_action*/ MSG_SIMPLE_Q_TAG,
-                             /*lba*/ 0,
-                             /*reladr*/ 0,
-                             /*pmi*/ 0,
-                             rcaplong,
-                             /*sense_len*/ SSD_FULL_SIZE,
-                             /*timeout*/ 60000);
+                                     /*retries*/ 4,
+                                     /*cbfcnp*/ dadone,
+                                     /*tag_action*/ MSG_SIMPLE_Q_TAG,
+                                     /*lba*/ 0,
+                                     /*reladr*/ 0,
+                                     /*pmi*/ 0,
+                                     /*rcap_buf*/ rcaplong,
+                                     /*sense_len*/ SSD_FULL_SIZE,
+                                     /*timeout*/ 60000);
                ccb->ccb_h.ccb_bp = NULL;
 
                error = cam_periph_runccb(ccb, daerror,
-                                 /*cam_flags*/CAM_RETRY_SELTO,
-                                 sense_flags,
-                                 softc->disk->d_devstat);
+                                         /*cam_flags*/CAM_RETRY_SELTO,
+                                         sense_flags, softc->disk->d_devstat);
                if (error == 0)
                        goto rc16ok;
 
                /* If we got ILLEGAL REQUEST, do not prefer RC16 any more. */
-               if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
-                    CAM_REQ_INVALID) {
+               if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INVALID) {
                        softc->flags &= ~DA_FLAG_CAN_RC16;
                } else if (((ccb->ccb_h.status & CAM_STATUS_MASK) ==
-                    CAM_SCSI_STATUS_ERROR) &&
-                   (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND) &&
-                   (ccb->ccb_h.status & CAM_AUTOSNS_VALID) &&
-                   ((ccb->ccb_h.flags & CAM_SENSE_PHYS) == 0) &&
-                   ((ccb->ccb_h.flags & CAM_SENSE_PTR) == 0)) {
+                            CAM_SCSI_STATUS_ERROR)
+                       && (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND)
+                       && (ccb->ccb_h.status & CAM_AUTOSNS_VALID)
+                       && ((ccb->ccb_h.flags & CAM_SENSE_PHYS) == 0)
+                       && ((ccb->ccb_h.flags & CAM_SENSE_PTR) == 0)) {
                        int sense_key, error_code, asc, ascq;
 
-                       scsi_extract_sense(&ccb->csio.sense_data,
-                                  &error_code, &sense_key, &asc, &ascq);
-                       if (sense_key == SSD_KEY_ILLEGAL_REQUEST)
+                       scsi_extract_sense_len(&ccb->csio.sense_data,
+                                              ccb->csio.sense_len -
+                                              ccb->csio.sense_resid,
+                                              &error_code, &sense_key,
+                                              &asc, &ascq, /*show_errors*/1);
+                       /*
+                        * If we don't have enough sense to get the sense
+                        * key, or if it's illegal request, turn off
+                        * READ CAPACITY (16).
+                        */
+                       if ((sense_key == -1)
+                        || (sense_key == SSD_KEY_ILLEGAL_REQUEST))
                                softc->flags &= ~DA_FLAG_CAN_RC16;
                }
                rc16failed = 1;
@@ -2652,9 +2668,9 @@ done:
                        error = EINVAL;
                } else {
                        dasetgeom(periph, block_len, maxsector,
-                           lbppbe, lalba & SRC16_LALBA);
-                       if ((lalba & SRC16_LBPME) &&
-                           softc->delete_method == DA_DELETE_NONE)
+                                 rcaplong, sizeof(*rcaplong));
+                       if ((lalba & SRC16_LBPME)
+                        && softc->delete_method == DA_DELETE_NONE)
                                softc->delete_method = DA_DELETE_UNMAP;
                }
        }
@@ -2668,17 +2684,27 @@ done:
 
 static void
 dasetgeom(struct cam_periph *periph, uint32_t block_len, uint64_t maxsector,
-    u_int lbppbe, u_int lalba)
+         struct scsi_read_capacity_data_long *rcaplong, size_t rcap_len)
 {
        struct ccb_calc_geometry ccg;
        struct da_softc *softc;
        struct disk_params *dp;
+       u_int lbppbe, lalba;
 
        softc = (struct da_softc *)periph->softc;
 
        dp = &softc->params;
        dp->secsize = block_len;
        dp->sectors = maxsector + 1;
+       if (rcaplong != NULL) {
+               lbppbe = rcaplong->prot_lbppbe & SRC16_LBPPBE;
+               lalba = scsi_2btoul(rcaplong->lalba_lbp);
+               lalba &= SRC16_LALBA_A;
+       } else {
+               lbppbe = 0;
+               lalba = 0;
+       }
+
        if (lbppbe > 0) {
                dp->stripesize = block_len << lbppbe;
                dp->stripeoffset = (dp->stripesize - block_len * lalba) %
@@ -2723,6 +2749,38 @@ dasetgeom(struct cam_periph *periph, uin
                dp->secs_per_track = ccg.secs_per_track;
                dp->cylinders = ccg.cylinders;
        }
+
+       /*
+        * If the user supplied a read capacity buffer, and if it is
+        * different than the previous buffer, update the data in the EDT.
+        * If it's the same, we don't bother.  This avoids sending an
+        * update every time someone opens this device.
+        */
+       if ((rcaplong != NULL)
+        && (bcmp(rcaplong, &softc->rcaplong,
+                 min(sizeof(softc->rcaplong), rcap_len)) != 0)) {
+               struct ccb_dev_advinfo cdai;
+
+               xpt_setup_ccb(&cdai.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
+               cdai.ccb_h.func_code = XPT_DEV_ADVINFO;
+               cdai.buftype = CDAI_TYPE_RCAPLONG;
+               cdai.flags |= CDAI_FLAG_STORE;
+               cdai.bufsiz = rcap_len;
+               cdai.buf = (uint8_t *)rcaplong;
+               xpt_action((union ccb *)&cdai);
+               if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0)
+                       cam_release_devq(cdai.ccb_h.path, 0, 0, 0, FALSE);
+               if (cdai.ccb_h.status != CAM_REQ_CMP) {
+                       xpt_print(periph->path, "%s: failed to set read "
+                                 "capacity advinfo\n", __func__);
+                       /* Use cam_error_print() to decode the status */
+                       cam_error_print((union ccb *)&cdai, CAM_ESF_CAM_STATUS,
+                                       CAM_EPF_ALL);
+               } else {
+                       bcopy(rcaplong, &softc->rcaplong,
+                             min(sizeof(softc->rcaplong), rcap_len));
+               }
+       }
 }
 
 static void

Modified: stable/9/sys/cam/scsi/scsi_xpt.c
==============================================================================
--- stable/9/sys/cam/scsi/scsi_xpt.c    Thu Feb 21 17:54:14 2013        
(r247110)
+++ stable/9/sys/cam/scsi/scsi_xpt.c    Thu Feb 21 18:15:41 2013        
(r247111)
@@ -2473,8 +2473,10 @@ scsi_dev_advinfo(union ccb *start_ccb)
                break;
        case CDAI_TYPE_PHYS_PATH:
                if (cdai->flags & CDAI_FLAG_STORE) {
-                       if (device->physpath != NULL)
+                       if (device->physpath != NULL) {
                                free(device->physpath, M_CAMXPT);
+                               device->physpath = NULL;
+                       }
                        device->physpath_len = cdai->bufsiz;
                        /* Clear existing buffer if zero length */
                        if (cdai->bufsiz == 0)
@@ -2495,6 +2497,36 @@ scsi_dev_advinfo(union ccb *start_ccb)
                        memcpy(cdai->buf, device->physpath, amt);
                }
                break;
+       case CDAI_TYPE_RCAPLONG:
+               if (cdai->flags & CDAI_FLAG_STORE) {
+                       if (device->rcap_buf != NULL) {
+                               free(device->rcap_buf, M_CAMXPT);
+                               device->rcap_buf = NULL;
+                       }
+
+                       device->rcap_len = cdai->bufsiz;
+                       /* Clear existing buffer if zero length */
+                       if (cdai->bufsiz == 0)
+                               break;
+
+                       device->rcap_buf = malloc(cdai->bufsiz, M_CAMXPT,
+                                                 M_NOWAIT);
+                       if (device->rcap_buf == NULL) {
+                               start_ccb->ccb_h.status = CAM_REQ_ABORTED;
+                               return;
+                       }
+
+                       memcpy(device->rcap_buf, cdai->buf, cdai->bufsiz);
+               } else {
+                       cdai->provsiz = device->rcap_len;
+                       if (device->rcap_len == 0)
+                               break;
+                       amt = device->rcap_len;
+                       if (cdai->provsiz > cdai->bufsiz)
+                               amt = cdai->bufsiz;
+                       memcpy(cdai->buf, device->rcap_buf, amt);
+               }
+               break;
        default:
                return;
        }
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to