diff options
author | Alan Perry <Alan.Perry@Sun.COM> | 2010-03-26 15:39:18 -0700 |
---|---|---|
committer | Alan Perry <Alan.Perry@Sun.COM> | 2010-03-26 15:39:18 -0700 |
commit | 0bc523e585d34fb799f65e1c4fd7d163e401a501 (patch) | |
tree | 74634b3bdc734b492b93c0d17dcc0b5beb427ed1 /usr/src | |
parent | 6e91bba0d6c6bdabbba62cefae583715a4a58e2a (diff) | |
download | illumos-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.c | 181 | ||||
-rw-r--r-- | usr/src/uts/common/io/scsi/targets/sd.c | 8 | ||||
-rw-r--r-- | usr/src/uts/common/sys/sata/impl/sata.h | 4 | ||||
-rw-r--r-- | usr/src/uts/common/sys/sata/sata_defs.h | 8 |
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 |