Mercurial > illumos > illumos-gate
changeset 12017:2ff17b2a8ff9
6922272 SATA framework does not handle >2TiB disks
6937622 DKIOCGMEDIAINFOEXT returns the wrong physical block size
author | Alan Perry <Alan.Perry@Sun.COM> |
---|---|
date | Fri, 26 Mar 2010 15:39:18 -0700 |
parents | 0248e987199b |
children | 78c92c5b916f |
files | usr/src/uts/common/io/sata/impl/sata.c usr/src/uts/common/io/scsi/targets/sd.c usr/src/uts/common/sys/sata/impl/sata.h usr/src/uts/common/sys/sata/sata_defs.h |
diffstat | 4 files changed, 193 insertions(+), 8 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/uts/common/io/sata/impl/sata.c Fri Mar 26 17:53:11 2010 -0400 +++ b/usr/src/uts/common/io/sata/impl/sata.c Fri Mar 26 15:39:18 2010 -0700 @@ -201,6 +201,7 @@ 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 @@ * 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 @@ 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 @@ 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 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.
--- a/usr/src/uts/common/io/scsi/targets/sd.c Fri Mar 26 17:53:11 2010 -0400 +++ b/usr/src/uts/common/io/scsi/targets/sd.c Fri Mar 26 15:39:18 2010 -0700 @@ -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 @@ } /* - * 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 @@ */ 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;
--- a/usr/src/uts/common/sys/sata/impl/sata.h Fri Mar 26 17:53:11 2010 -0400 +++ b/usr/src/uts/common/sys/sata/impl/sata.h Fri Mar 26 15:39:18 2010 -0700 @@ -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 @@ * 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
--- a/usr/src/uts/common/sys/sata/sata_defs.h Fri Mar 26 17:53:11 2010 -0400 +++ b/usr/src/uts/common/sys/sata/sata_defs.h Fri Mar 26 15:39:18 2010 -0700 @@ -314,6 +314,12 @@ /* 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 @@ /* * 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