From owner-svn-src-stable@FreeBSD.ORG Tue Mar 13 20:33:16 2012 Return-Path: Delivered-To: svn-src-stable@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 766231065674; Tue, 13 Mar 2012 20:33:16 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 649A68FC12; Tue, 13 Mar 2012 20:33:16 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q2DKXGBd061637; Tue, 13 Mar 2012 20:33:16 GMT (envelope-from mav@svn.freebsd.org) Received: (from mav@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q2DKXGtm061634; Tue, 13 Mar 2012 20:33:16 GMT (envelope-from mav@svn.freebsd.org) Message-Id: <201203132033.q2DKXGtm061634@svn.freebsd.org> From: Alexander Motin Date: Tue, 13 Mar 2012 20:33:16 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org X-SVN-Group: stable-9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r232941 - stable/9/sys/cam/scsi X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 13 Mar 2012 20:33:16 -0000 Author: mav Date: Tue Mar 13 20:33:15 2012 New Revision: 232941 URL: http://svn.freebsd.org/changeset/base/232941 Log: MFC r228846: Use READ CAPACITY(16) to get information about device physical sectors. As soon as not all devices support READ CAPACITY(16), automatically fall back to READ CAPACITY(10) if CAM_REQ_INVALID or SSD_KEY_ILLEGAL_REQUEST status returned. It also provides first bits of information about Logical Block Provisioning (aka UNMAP/TRIM) support by the device. Modified: stable/9/sys/cam/scsi/scsi_all.h stable/9/sys/cam/scsi/scsi_da.c Directory Properties: stable/9/sys/ (props changed) Modified: stable/9/sys/cam/scsi/scsi_all.h ============================================================================== --- stable/9/sys/cam/scsi/scsi_all.h Tue Mar 13 20:30:23 2012 (r232940) +++ stable/9/sys/cam/scsi/scsi_all.h Tue Mar 13 20:33:15 2012 (r232941) @@ -1397,6 +1397,17 @@ struct scsi_read_capacity_data_long { uint8_t addr[8]; uint8_t length[4]; +#define SRC16_PROT_EN 0x01 +#define SRC16_P_TYPE 0x0e + 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 + uint8_t lalba_lbp[2]; }; struct scsi_report_luns Modified: stable/9/sys/cam/scsi/scsi_da.c ============================================================================== --- stable/9/sys/cam/scsi/scsi_da.c Tue Mar 13 20:30:23 2012 (r232940) +++ stable/9/sys/cam/scsi/scsi_da.c Tue Mar 13 20:33:15 2012 (r232941) @@ -82,7 +82,9 @@ typedef enum { DA_FLAG_WENT_IDLE = 0x040, DA_FLAG_RETRY_UA = 0x080, DA_FLAG_OPEN = 0x100, - DA_FLAG_SCTX_INIT = 0x200 + DA_FLAG_SCTX_INIT = 0x200, + DA_FLAG_CAN_RC16 = 0x400, + DA_FLAG_CAN_LBPME = 0x800 } da_flags; typedef enum { @@ -1544,6 +1546,14 @@ daregister(struct cam_periph *periph, vo else if (softc->minimum_cmd_size > 12) softc->minimum_cmd_size = 16; + /* Predict whether device may support READ CAPACITY(16). */ + if (SID_ANSI_REV(&cgd->inq_data) >= SCSI_REV_SPC3 || + (SID_ANSI_REV(&cgd->inq_data) >= SCSI_REV_SPC && + (cgd->inq_data.spc3_flags & SPC3_SID_PROTECT))) { + softc->flags |= DA_FLAG_CAN_RC16; + softc->state = DA_STATE_PROBE2; + } + /* * Register this media as a disk. */ @@ -1940,10 +1950,14 @@ dadone(struct cam_periph *periph, union struct disk_params *dp; uint32_t block_size; uint64_t maxsector; + u_int lbppbe; /* LB per physical block exponent. */ + u_int lalba; /* Lowest aligned LBA. */ if (softc->state == DA_STATE_PROBE) { block_size = scsi_4btoul(rdcap->length); maxsector = scsi_4btoul(rdcap->addr); + lbppbe = 0; + lalba = 0; /* * According to SBC-2, if the standard 10 @@ -1963,6 +1977,8 @@ dadone(struct cam_periph *periph, union } else { block_size = scsi_4btoul(rcaplong->length); maxsector = scsi_8btou64(rcaplong->addr); + lbppbe = rcaplong->prot_lbppbe & SRC16_LBPPBE; + lalba = scsi_2btoul(rcaplong->lalba_lbp); } /* @@ -1980,7 +1996,12 @@ dadone(struct cam_periph *periph, union announce_buf[0] = '\0'; cam_periph_invalidate(periph); } else { - dasetgeom(periph, block_size, maxsector, 0, 0); + dasetgeom(periph, block_size, maxsector, + lbppbe, lalba & SRC16_LALBA); + if (lalba & SRC16_LBPME) + softc->flags |= DA_FLAG_CAN_LBPME; + else + softc->flags &= ~DA_FLAG_CAN_LBPME; dp = &softc->params; snprintf(announce_buf, sizeof(announce_buf), "%juMB (%ju %u byte sectors: %dH %dS/T " @@ -2047,6 +2068,24 @@ dadone(struct cam_periph *periph, union &ascq, /*show_errors*/ 1); } /* + * If we tried READ CAPACITY(16) and failed, + * fallback to READ CAPACITY(10). + */ + if ((softc->state == DA_STATE_PROBE2) && + (softc->flags & DA_FLAG_CAN_RC16) && + (((csio->ccb_h.status & CAM_STATUS_MASK) == + CAM_REQ_INVALID) || + ((have_sense) && + (error_code == SSD_CURRENT_ERROR) && + (sense_key == SSD_KEY_ILLEGAL_REQUEST)))) { + softc->flags &= ~DA_FLAG_CAN_RC16; + softc->state = DA_STATE_PROBE; + free(rdcap, M_SCSIDA); + xpt_release_ccb(done_ccb); + xpt_schedule(periph, priority); + return; + } else + /* * Attach to anything that claims to be a * direct access or optical disk device, * as long as it doesn't return a "Logical @@ -2223,13 +2262,18 @@ dagetcapacity(struct cam_periph *periph) struct scsi_read_capacity_data_long *rcaplong; uint32_t block_len; uint64_t maxsector; - int error; + int error, rc16failed; u_int32_t sense_flags; + u_int lbppbe; /* Logical blocks per physical block exponent. */ + u_int lalba; /* Lowest aligned LBA. */ softc = (struct da_softc *)periph->softc; block_len = 0; maxsector = 0; + lbppbe = 0; + lalba = 0; error = 0; + rc16failed = 0; sense_flags = SF_RETRY_UA; if (softc->flags & DA_FLAG_PACK_REMOVABLE) sense_flags |= SF_NO_PRINT; @@ -2237,11 +2281,63 @@ dagetcapacity(struct cam_periph *periph) /* Do a read capacity */ rcap = (struct scsi_read_capacity_data *)malloc(sizeof(*rcaplong), M_SCSIDA, - M_NOWAIT); + M_NOWAIT | M_ZERO); if (rcap == NULL) return (ENOMEM); - + rcaplong = (struct scsi_read_capacity_data_long *)rcap; + ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); + + /* 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); + ccb->ccb_h.ccb_bp = NULL; + + error = cam_periph_runccb(ccb, daerror, + /*cam_flags*/CAM_RETRY_SELTO, + sense_flags, + softc->disk->d_devstat); + + if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) + cam_release_devq(ccb->ccb_h.path, + /*relsim_flags*/0, + /*reduction*/0, + /*timeout*/0, + /*getcount_only*/0); + + 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) { + 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)) { + 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) + softc->flags &= ~DA_FLAG_CAN_RC16; + } + rc16failed = 1; + } + + /* Do READ CAPACITY(10). */ scsi_read_capacity(&ccb->csio, /*retries*/4, /*cbfncp*/dadone, @@ -2267,13 +2363,12 @@ dagetcapacity(struct cam_periph *periph) block_len = scsi_4btoul(rcap->length); maxsector = scsi_4btoul(rcap->addr); - if (maxsector != 0xffffffff) + if (maxsector != 0xffffffff || rc16failed) goto done; } else goto done; - rcaplong = (struct scsi_read_capacity_data_long *)rcap; - + /* If READ CAPACITY(10) returned overflow, use READ CAPACITY(16) */ scsi_read_capacity_16(&ccb->csio, /*retries*/ 4, /*cbfcnp*/ dadone, @@ -2299,8 +2394,11 @@ dagetcapacity(struct cam_periph *periph) /*getcount_only*/0); if (error == 0) { +rc16ok: block_len = scsi_4btoul(rcaplong->length); maxsector = scsi_8btou64(rcaplong->addr); + lbppbe = rcaplong->prot_lbppbe & SRC16_LBPPBE; + lalba = scsi_2btoul(rcaplong->lalba_lbp); } done: @@ -2311,8 +2409,14 @@ done: "unsupportable block size %ju\n", (uintmax_t) block_len); error = EINVAL; - } else - dasetgeom(periph, block_len, maxsector, 0, 0); + } else { + dasetgeom(periph, block_len, maxsector, + lbppbe, lalba & SRC16_LALBA); + if (lalba & SRC16_LBPME) + softc->flags |= DA_FLAG_CAN_LBPME; + else + softc->flags &= ~DA_FLAG_CAN_LBPME; + } } xpt_release_ccb(ccb);