summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorAlan Perry <Alan.Perry@Sun.COM>2010-03-26 15:39:18 -0700
committerAlan Perry <Alan.Perry@Sun.COM>2010-03-26 15:39:18 -0700
commit0bc523e585d34fb799f65e1c4fd7d163e401a501 (patch)
tree74634b3bdc734b492b93c0d17dcc0b5beb427ed1 /usr/src
parent6e91bba0d6c6bdabbba62cefae583715a4a58e2a (diff)
downloadillumos-joyent-0bc523e585d34fb799f65e1c4fd7d163e401a501.tar.gz
6922272 SATA framework does not handle >2TiB disks
6937622 DKIOCGMEDIAINFOEXT returns the wrong physical block size
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/uts/common/io/sata/impl/sata.c181
-rw-r--r--usr/src/uts/common/io/scsi/targets/sd.c8
-rw-r--r--usr/src/uts/common/sys/sata/impl/sata.h4
-rw-r--r--usr/src/uts/common/sys/sata/sata_defs.h8
4 files changed, 193 insertions, 8 deletions
diff --git a/usr/src/uts/common/io/sata/impl/sata.c b/usr/src/uts/common/io/sata/impl/sata.c
index 42fd970056..0919e10f7d 100644
--- a/usr/src/uts/common/io/sata/impl/sata.c
+++ b/usr/src/uts/common/io/sata/impl/sata.c
@@ -201,6 +201,7 @@ static int sata_txlt_inquiry(sata_pkt_txlate_t *);
static int sata_txlt_test_unit_ready(sata_pkt_txlate_t *);
static int sata_txlt_start_stop_unit(sata_pkt_txlate_t *);
static int sata_txlt_read_capacity(sata_pkt_txlate_t *);
+static int sata_txlt_read_capacity16(sata_pkt_txlate_t *);
static int sata_txlt_request_sense(sata_pkt_txlate_t *);
static int sata_txlt_read(sata_pkt_txlate_t *);
static int sata_txlt_write(sata_pkt_txlate_t *);
@@ -2337,6 +2338,7 @@ sata_scsi_init_pkt(struct scsi_address *ap, struct scsi_pkt *pkt,
* SCMD_TEST_UNIT_READY
* SCMD_START_STOP
* SCMD_READ_CAPACITY
+ * SCMD_SVC_ACTION_IN_G4 (READ CAPACITY (16))
* SCMD_REQUEST_SENSE
* SCMD_LOG_SENSE_G1
* SCMD_LOG_SELECT_G1
@@ -2513,6 +2515,12 @@ sata_scsi_start(struct scsi_address *ap, struct scsi_pkt *pkt)
rval = sata_txlt_read_capacity(spx);
break;
+ case SCMD_SVC_ACTION_IN_G4: /* READ CAPACITY (16) */
+ if (bp != NULL && (bp->b_flags & (B_PHYS | B_PAGEIO)))
+ bp_mapin(bp);
+ rval = sata_txlt_read_capacity16(spx);
+ break;
+
case SCMD_REQUEST_SENSE:
/*
* Always No Sense, since we force ARQ
@@ -4389,8 +4397,13 @@ sata_txlt_read_capacity(sata_pkt_txlate_t *spx)
sdinfo = sata_get_device_info(
spx->txlt_sata_hba_inst,
&spx->txlt_sata_pkt->satapkt_device);
- /* Last logical block address */
- val = sdinfo->satadrv_capacity - 1;
+
+ /*
+ * As per SBC-3, the "returned LBA" is either the highest
+ * addressable LBA or 0xffffffff, whichever is smaller.
+ */
+ val = MIN(sdinfo->satadrv_capacity - 1, UINT32_MAX);
+
rbuf = (uchar_t *)bp->b_un.b_addr;
/* Need to swap endians to match scsi format */
rbuf[0] = (val >> 24) & 0xff;
@@ -4436,6 +4449,170 @@ sata_txlt_read_capacity(sata_pkt_txlate_t *spx)
}
/*
+ * SATA translate command: Read Capacity (16).
+ * Emulated command for SATA disks.
+ * Info is retrieved from cached Identify Device data.
+ * Implemented to SBC-3 (draft 21) and SAT-2 (final) specifications.
+ *
+ * Returns TRAN_ACCEPT and appropriate values in scsi_pkt fields.
+ */
+static int
+sata_txlt_read_capacity16(sata_pkt_txlate_t *spx)
+{
+ struct scsi_pkt *scsipkt = spx->txlt_scsi_pkt;
+ struct buf *bp = spx->txlt_sata_pkt->satapkt_cmd.satacmd_bp;
+ sata_drive_info_t *sdinfo;
+ uint64_t val;
+ uint16_t l2p_exp;
+ uchar_t *rbuf;
+ int rval, reason;
+
+ SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst,
+ "sata_txlt_read_capacity: ", NULL);
+
+ mutex_enter(&(SATA_TXLT_CPORT_MUTEX(spx)));
+
+ if (((rval = sata_txlt_generic_pkt_info(spx, &reason, 0)) !=
+ TRAN_ACCEPT) || (reason == CMD_DEV_GONE)) {
+ mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx)));
+ return (rval);
+ }
+
+ scsipkt->pkt_reason = CMD_CMPLT;
+ scsipkt->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
+ STATE_SENT_CMD | STATE_GOT_STATUS;
+ if (bp != NULL && bp->b_un.b_addr && bp->b_bcount) {
+ /*
+ * Because it is fully emulated command storing data
+ * programatically in the specified buffer, release
+ * preallocated DMA resources before storing data in the buffer,
+ * so no unwanted DMA sync would take place.
+ */
+ sata_scsi_dmafree(NULL, scsipkt);
+
+ /* Check SERVICE ACTION field */
+ if ((scsipkt->pkt_cdbp[1] & 0x1f) !=
+ SSVC_ACTION_READ_CAPACITY_G4) {
+ mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx)));
+ return (sata_txlt_check_condition(spx,
+ KEY_ILLEGAL_REQUEST,
+ SD_SCSI_ASC_INVALID_FIELD_IN_CDB));
+ }
+
+ /* Check LBA field */
+ if ((scsipkt->pkt_cdbp[2] != 0) ||
+ (scsipkt->pkt_cdbp[3] != 0) ||
+ (scsipkt->pkt_cdbp[4] != 0) ||
+ (scsipkt->pkt_cdbp[5] != 0) ||
+ (scsipkt->pkt_cdbp[6] != 0) ||
+ (scsipkt->pkt_cdbp[7] != 0) ||
+ (scsipkt->pkt_cdbp[8] != 0) ||
+ (scsipkt->pkt_cdbp[9] != 0)) {
+ mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx)));
+ return (sata_txlt_check_condition(spx,
+ KEY_ILLEGAL_REQUEST,
+ SD_SCSI_ASC_INVALID_FIELD_IN_CDB));
+ }
+
+ /* Check PMI bit */
+ if (scsipkt->pkt_cdbp[14] & 0x1) {
+ mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx)));
+ return (sata_txlt_check_condition(spx,
+ KEY_ILLEGAL_REQUEST,
+ SD_SCSI_ASC_INVALID_FIELD_IN_CDB));
+ }
+
+ *scsipkt->pkt_scbp = STATUS_GOOD;
+
+ sdinfo = sata_get_device_info(
+ spx->txlt_sata_hba_inst,
+ &spx->txlt_sata_pkt->satapkt_device);
+
+ /* last logical block address */
+ val = MIN(sdinfo->satadrv_capacity - 1,
+ SCSI_READ_CAPACITY16_MAX_LBA);
+
+ /* logical to physical block size exponent */
+ l2p_exp = 0;
+ if (sdinfo->satadrv_id.ai_phys_sect_sz & SATA_L2PS_CHECK_BIT) {
+ /* physical/logical sector size word is valid */
+
+ if (sdinfo->satadrv_id.ai_phys_sect_sz &
+ SATA_L2PS_HAS_MULT) {
+ /* multiple logical sectors per phys sectors */
+ l2p_exp =
+ sdinfo->satadrv_id.ai_phys_sect_sz &
+ SATA_L2PS_EXP_MASK;
+ }
+ }
+
+ rbuf = (uchar_t *)bp->b_un.b_addr;
+ bzero(rbuf, bp->b_bcount);
+
+ /* returned logical block address */
+ rbuf[0] = (val >> 56) & 0xff;
+ rbuf[1] = (val >> 48) & 0xff;
+ rbuf[2] = (val >> 40) & 0xff;
+ rbuf[3] = (val >> 32) & 0xff;
+ rbuf[4] = (val >> 24) & 0xff;
+ rbuf[5] = (val >> 16) & 0xff;
+ rbuf[6] = (val >> 8) & 0xff;
+ rbuf[7] = val & 0xff;
+
+ /* logical block length in bytes = 512 (for now) */
+ /* rbuf[8] = 0; */
+ /* rbuf[9] = 0; */
+ rbuf[10] = 0x02;
+ /* rbuf[11] = 0; */
+
+ /* p_type, prot_en, unspecified by SAT-2 */
+ /* rbuf[12] = 0; */
+
+ /* p_i_exponent, undefined by SAT-2 */
+ /* logical blocks per physical block exponent */
+ rbuf[13] = l2p_exp;
+
+ /* tpe, tprz, undefined by SAT-2 */
+ /* lowest aligned logical block address = 0 (for now) */
+ /* rbuf[14] = 0; */
+ /* rbuf[15] = 0; */
+
+ scsipkt->pkt_state |= STATE_XFERRED_DATA;
+ scsipkt->pkt_resid = 0;
+
+ SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst, "%llu\n",
+ sdinfo->satadrv_capacity -1);
+ }
+
+ mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx)));
+
+ /*
+ * If a callback was requested, do it now.
+ */
+ SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst,
+ "Scsi_pkt completion reason %x\n", scsipkt->pkt_reason);
+
+ if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0 &&
+ scsipkt->pkt_comp != NULL) {
+ /* scsi callback required */
+ if (servicing_interrupt()) {
+ if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+ (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+ (void *)spx->txlt_scsi_pkt, TQ_NOSLEEP) == NULL) {
+ return (TRAN_BUSY);
+ }
+ } else if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+ (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+ (void *)spx->txlt_scsi_pkt, TQ_SLEEP) == NULL) {
+ /* Scheduling the callback failed */
+ return (TRAN_BUSY);
+ }
+ }
+
+ return (TRAN_ACCEPT);
+}
+
+/*
* SATA translate command: Mode Sense.
* Translated into appropriate SATA command or emulated.
* Saved Values Page Control (03) are not supported.
diff --git a/usr/src/uts/common/io/scsi/targets/sd.c b/usr/src/uts/common/io/scsi/targets/sd.c
index eb57ec143b..26d7576a9c 100644
--- a/usr/src/uts/common/io/scsi/targets/sd.c
+++ b/usr/src/uts/common/io/scsi/targets/sd.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -20190,11 +20190,11 @@ sd_send_scsi_READ_CAPACITY_16(sd_ssc_t *ssc, uint64_t *capp,
}
/*
- * Read capacity and block size from the READ CAPACITY 10 data.
+ * Read capacity and block size from the READ CAPACITY 16 data.
* This data may be adjusted later due to device specific
* issues.
*
- * According to the SCSI spec, the READ CAPACITY 10
+ * According to the SCSI spec, the READ CAPACITY 16
* command returns the following:
*
* bytes 0-7: Maximum logical block address available.
@@ -20207,7 +20207,7 @@ sd_send_scsi_READ_CAPACITY_16(sd_ssc_t *ssc, uint64_t *capp,
*/
capacity = BE_64(capacity16_buf[0]);
lbasize = BE_32(*(uint32_t *)&capacity16_buf[1]);
- lbpb_exp = (BE_64(capacity16_buf[1]) >> 40) & 0x0f;
+ lbpb_exp = (BE_64(capacity16_buf[1]) >> 16) & 0x0f;
pbsize = lbasize << lbpb_exp;
diff --git a/usr/src/uts/common/sys/sata/impl/sata.h b/usr/src/uts/common/sys/sata/impl/sata.h
index 692dd146ef..39999011d9 100644
--- a/usr/src/uts/common/sys/sata/impl/sata.h
+++ b/usr/src/uts/common/sys/sata/impl/sata.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -543,6 +543,8 @@ struct sata_apt_sense_data {
* in sys/scsi/targets/sddefs.h as MODEPAGE_ERR_RECOV
*/
#define MODEPAGE_RW_ERRRECOV 0x01 /* read/write recovery */
+/* Missing from sys/scsi/impl/commands.h */
+#define SCSI_READ_CAPACITY16_MAX_LBA 0xfffffffffffffffe
/*
* medium access command
diff --git a/usr/src/uts/common/sys/sata/sata_defs.h b/usr/src/uts/common/sys/sata/sata_defs.h
index 67c817ccc4..f14955579b 100644
--- a/usr/src/uts/common/sys/sata/sata_defs.h
+++ b/usr/src/uts/common/sys/sata/sata_defs.h
@@ -314,6 +314,12 @@ typedef struct sata_id {
/* IDLE IMMEDIATE with UNLOAD FEATURE supported */
#define SATA_IDLE_UNLOAD_SUPPORTED 0x2000
+/* Identify Device: physical sector size - word 106 */
+#define SATA_L2PS_CHECK_BIT 0x4000 /* Set when this word valid */
+#define SATA_L2PS_HAS_MULT 0x2000 /* Multiple logical sectors per phys */
+#define SATA_L2PS_BIG_SECTORS 0x1000 /* Logical sector size > 512 */
+#define SATA_L2PS_EXP_MASK 0x000f /* Logical sectors per phys exponent */
+
/* Identify (Packet) Device word 63, ATA/ATAPI-6 & 7 */
#define SATA_MDMA_SEL_MASK 0x0700 /* Multiword DMA selected */
#define SATA_MDMA_2_SEL 0x0400 /* Multiword DMA mode 2 selected */
@@ -612,7 +618,7 @@ struct read_log_ext_directory {
/*
* SMART specific data
- * These eventually need to go to a generic scsi hearder file
+ * These eventually need to go to a generic scsi header file
* for now they will reside here
*/
#define PC_CUMULATIVE_VALUES 0x01