diff options
Diffstat (limited to 'usr/src/uts/common')
-rw-r--r-- | usr/src/uts/common/io/nvme/nvme.c | 104 | ||||
-rw-r--r-- | usr/src/uts/common/io/nvme/nvme_var.h | 3 | ||||
-rw-r--r-- | usr/src/uts/common/io/sata/impl/sata.c | 42 |
3 files changed, 88 insertions, 61 deletions
diff --git a/usr/src/uts/common/io/nvme/nvme.c b/usr/src/uts/common/io/nvme/nvme.c index 1cb0389063..41ee79f0ed 100644 --- a/usr/src/uts/common/io/nvme/nvme.c +++ b/usr/src/uts/common/io/nvme/nvme.c @@ -11,6 +11,8 @@ /* * Copyright 2016 Nexenta Systems, Inc. All rights reserved. + * Copyright 2016 Tegile Systems, Inc. All rights reserved. + * Copyright (c) 2016 The MathWorks, Inc. All rights reserved. */ /* @@ -190,6 +192,9 @@ static const int nvme_version_major = 1; static const int nvme_version_minor = 0; +/* tunable for admin command timeout in seconds, default is 1s */ +static volatile int nvme_admin_cmd_timeout = 1; + static int nvme_attach(dev_info_t *, ddi_attach_cmd_t); static int nvme_detach(dev_info_t *, ddi_detach_cmd_t); static int nvme_quiesce(dev_info_t *); @@ -268,7 +273,7 @@ static ddi_dma_attr_t nvme_queue_dma_attr = { .dma_attr_version = DMA_ATTR_V0, .dma_attr_addr_lo = 0, .dma_attr_addr_hi = 0xffffffffffffffffULL, - .dma_attr_count_max = (UINT16_MAX + 1) * sizeof (nvme_sqe_t), + .dma_attr_count_max = (UINT16_MAX + 1) * sizeof (nvme_sqe_t) - 1, .dma_attr_align = 0x1000, .dma_attr_burstsizes = 0x7ff, .dma_attr_minxfer = 0x1000, @@ -296,7 +301,7 @@ static ddi_dma_attr_t nvme_prp_dma_attr = { .dma_attr_burstsizes = 0x7ff, .dma_attr_minxfer = 0x1000, .dma_attr_maxxfer = 0x1000, - .dma_attr_seg = 0xffffffffffffffffULL, + .dma_attr_seg = 0xfff, .dma_attr_sgllen = -1, .dma_attr_granular = 1, .dma_attr_flags = 0, @@ -782,7 +787,7 @@ nvme_check_vendor_cmd_status(nvme_cmd_t *cmd) "sc = %x, sct = %x, dnr = %d, m = %d", cmd->nc_sqe.sqe_opc, cqe->cqe_sqid, cqe->cqe_cid, cqe->cqe_sf.sf_sc, cqe->cqe_sf.sf_sct, cqe->cqe_sf.sf_dnr, cqe->cqe_sf.sf_m); - if (cmd->nc_nvme->n_ignore_unknown_vendor_status) { + if (!cmd->nc_nvme->n_ignore_unknown_vendor_status) { cmd->nc_nvme->n_dead = B_TRUE; ddi_fm_service_impact(cmd->nc_nvme->n_dip, DDI_SERVICE_LOST); } @@ -1083,7 +1088,7 @@ nvme_abort_cmd(nvme_cmd_t *abort_cmd) * Send the ABORT to the hardware. The ABORT command will return _after_ * the aborted command has completed (aborted or otherwise). */ - if (nvme_admin_cmd(cmd, NVME_ADMIN_CMD_TIMEOUT) != DDI_SUCCESS) { + if (nvme_admin_cmd(cmd, nvme_admin_cmd_timeout) != DDI_SUCCESS) { sema_v(&nvme->n_abort_sema); dev_err(nvme->n_dip, CE_WARN, "!nvme_admin_cmd failed for ABORT"); @@ -1117,9 +1122,9 @@ nvme_abort_cmd(nvme_cmd_t *abort_cmd) * will be declared dead and FMA will be notified. */ static boolean_t -nvme_wait_cmd(nvme_cmd_t *cmd, uint_t usec) +nvme_wait_cmd(nvme_cmd_t *cmd, uint_t sec) { - clock_t timeout = ddi_get_lbolt() + drv_usectohz(usec); + clock_t timeout = ddi_get_lbolt() + drv_usectohz(sec * MICROSEC); nvme_t *nvme = cmd->nc_nvme; nvme_reg_csts_t csts; @@ -1353,7 +1358,7 @@ nvme_async_event_task(void *arg) } static int -nvme_admin_cmd(nvme_cmd_t *cmd, int usec) +nvme_admin_cmd(nvme_cmd_t *cmd, int sec) { int ret; @@ -1369,7 +1374,7 @@ nvme_admin_cmd(nvme_cmd_t *cmd, int usec) return (DDI_FAILURE); } - if (nvme_wait_cmd(cmd, usec) == B_FALSE) { + if (nvme_wait_cmd(cmd, sec) == B_FALSE) { /* * The command timed out. An abort command was posted that * will take care of the cleanup. @@ -1408,7 +1413,7 @@ nvme_get_logpage(nvme_t *nvme, uint8_t logpage, ...) { nvme_cmd_t *cmd = nvme_alloc_cmd(nvme, KM_SLEEP); void *buf = NULL; - nvme_getlogpage_t getlogpage; + nvme_getlogpage_t getlogpage = { 0 }; size_t bufsize; va_list ap; @@ -1472,7 +1477,7 @@ nvme_get_logpage(nvme_t *nvme, uint8_t logpage, ...) cmd->nc_dma->nd_cookie.dmac_laddress; } - if (nvme_admin_cmd(cmd, NVME_ADMIN_CMD_TIMEOUT) != DDI_SUCCESS) { + if (nvme_admin_cmd(cmd, nvme_admin_cmd_timeout) != DDI_SUCCESS) { dev_err(nvme->n_dip, CE_WARN, "!nvme_admin_cmd failed for GET LOG PAGE"); return (NULL); @@ -1528,7 +1533,7 @@ nvme_identify(nvme_t *nvme, uint32_t nsid) cmd->nc_dma->nd_cookie.dmac_laddress; } - if (nvme_admin_cmd(cmd, NVME_ADMIN_CMD_TIMEOUT) != DDI_SUCCESS) { + if (nvme_admin_cmd(cmd, nvme_admin_cmd_timeout) != DDI_SUCCESS) { dev_err(nvme->n_dip, CE_WARN, "!nvme_admin_cmd failed for IDENTIFY"); return (NULL); @@ -1556,7 +1561,7 @@ nvme_set_nqueues(nvme_t *nvme, uint16_t nqueues) nvme_cmd_t *cmd = nvme_alloc_cmd(nvme, KM_SLEEP); nvme_nqueue_t nq = { 0 }; - nq.b.nq_nsq = nq.b.nq_ncq = nqueues; + nq.b.nq_nsq = nq.b.nq_ncq = nqueues - 1; cmd->nc_sqid = 0; cmd->nc_callback = nvme_wakeup_cmd; @@ -1564,7 +1569,7 @@ nvme_set_nqueues(nvme_t *nvme, uint16_t nqueues) cmd->nc_sqe.sqe_cdw10 = NVME_FEAT_NQUEUES; cmd->nc_sqe.sqe_cdw11 = nq.r; - if (nvme_admin_cmd(cmd, NVME_ADMIN_CMD_TIMEOUT) != DDI_SUCCESS) { + if (nvme_admin_cmd(cmd, nvme_admin_cmd_timeout) != DDI_SUCCESS) { dev_err(nvme->n_dip, CE_WARN, "!nvme_admin_cmd failed for SET FEATURES (NQUEUES)"); return (0); @@ -1585,7 +1590,7 @@ nvme_set_nqueues(nvme_t *nvme, uint16_t nqueues) * Always use the same number of submission and completion queues, and * never use more than the requested number of queues. */ - return (MIN(nqueues, MIN(nq.b.nq_nsq, nq.b.nq_ncq))); + return (MIN(nqueues, MIN(nq.b.nq_nsq, nq.b.nq_ncq) + 1)); } static int @@ -1610,7 +1615,7 @@ nvme_create_io_qpair(nvme_t *nvme, nvme_qpair_t *qp, uint16_t idx) cmd->nc_sqe.sqe_cdw11 = c_dw11.r; cmd->nc_sqe.sqe_dptr.d_prp[0] = qp->nq_cqdma->nd_cookie.dmac_laddress; - if (nvme_admin_cmd(cmd, NVME_ADMIN_CMD_TIMEOUT) != DDI_SUCCESS) { + if (nvme_admin_cmd(cmd, nvme_admin_cmd_timeout) != DDI_SUCCESS) { dev_err(nvme->n_dip, CE_WARN, "!nvme_admin_cmd failed for CREATE CQUEUE"); return (DDI_FAILURE); @@ -1637,7 +1642,7 @@ nvme_create_io_qpair(nvme_t *nvme, nvme_qpair_t *qp, uint16_t idx) cmd->nc_sqe.sqe_cdw11 = s_dw11.r; cmd->nc_sqe.sqe_dptr.d_prp[0] = qp->nq_sqdma->nd_cookie.dmac_laddress; - if (nvme_admin_cmd(cmd, NVME_ADMIN_CMD_TIMEOUT) != DDI_SUCCESS) { + if (nvme_admin_cmd(cmd, nvme_admin_cmd_timeout) != DDI_SUCCESS) { dev_err(nvme->n_dip, CE_WARN, "!nvme_admin_cmd failed for CREATE SQUEUE"); return (DDI_FAILURE); @@ -1746,14 +1751,6 @@ nvme_init(nvme_t *nvme) char model[sizeof (nvme->n_idctl->id_model) + 1]; char *vendor, *product; - /* Setup fixed interrupt for admin queue. */ - if (nvme_setup_interrupts(nvme, DDI_INTR_TYPE_FIXED, 1) - != DDI_SUCCESS) { - dev_err(nvme->n_dip, CE_WARN, - "!failed to setup fixed interrupt"); - goto fail; - } - /* Check controller version */ vs.r = nvme_get32(nvme, NVME_REG_VS); dev_err(nvme->n_dip, CE_CONT, "?NVMe spec version %d.%d", @@ -1806,6 +1803,7 @@ nvme_init(nvme_t *nvme) nvme->n_prp_dma_attr.dma_attr_maxxfer = nvme->n_pagesize; nvme->n_prp_dma_attr.dma_attr_minxfer = nvme->n_pagesize; nvme->n_prp_dma_attr.dma_attr_align = nvme->n_pagesize; + nvme->n_prp_dma_attr.dma_attr_seg = nvme->n_pagesize - 1; /* * Reset controller if it's still in ready state. @@ -1845,11 +1843,13 @@ nvme_init(nvme_t *nvme) nvme_put64(nvme, NVME_REG_ASQ, asq); nvme_put64(nvme, NVME_REG_ACQ, acq); - cc.b.cc_ams = 0; /* use Round-Robin arbitration */ - cc.b.cc_css = 0; /* use NVM command set */ + cc.b.cc_ams = 0; /* use Round-Robin arbitration */ + cc.b.cc_css = 0; /* use NVM command set */ cc.b.cc_mps = nvme->n_pageshift - 12; - cc.b.cc_shn = 0; /* no shutdown in progress */ - cc.b.cc_en = 1; /* enable controller */ + cc.b.cc_shn = 0; /* no shutdown in progress */ + cc.b.cc_en = 1; /* enable controller */ + cc.b.cc_iosqes = 6; /* submission queue entry is 2^6 bytes long */ + cc.b.cc_iocqes = 4; /* completion queue entry is 2^4 bytes long */ nvme_put32(nvme, NVME_REG_CC, cc.r); @@ -1890,6 +1890,20 @@ nvme_init(nvme_t *nvme) sema_init(&nvme->n_abort_sema, 1, NULL, SEMA_DRIVER, NULL); /* + * Setup initial interrupt for admin queue. + */ + if ((nvme_setup_interrupts(nvme, DDI_INTR_TYPE_MSIX, 1) + != DDI_SUCCESS) && + (nvme_setup_interrupts(nvme, DDI_INTR_TYPE_MSI, 1) + != DDI_SUCCESS) && + (nvme_setup_interrupts(nvme, DDI_INTR_TYPE_FIXED, 1) + != DDI_SUCCESS)) { + dev_err(nvme->n_dip, CE_WARN, + "!failed to setup initial interrupt"); + goto fail; + } + + /* * Post an asynchronous event command to catch errors. */ if (nvme_async_event(nvme) != DDI_SUCCESS) { @@ -2038,7 +2052,7 @@ nvme_init(nvme_t *nvme) * performance. A value of 3 means "degraded", 0 is best. */ last_rp = 3; - for (int j = 0; j != idns->id_nlbaf; j++) { + for (int j = 0; j <= idns->id_nlbaf; j++) { if (idns->id_lbaf[j].lbaf_lbads == 0) break; if (idns->id_lbaf[j].lbaf_ms != 0) @@ -2114,8 +2128,8 @@ nvme_init(nvme_t *nvme) if (nvme->n_ioq_count < nqueues) { nvme_release_interrupts(nvme); - if (nvme_setup_interrupts(nvme, nvme->n_intr_type, nqueues) - != DDI_SUCCESS) { + if (nvme_setup_interrupts(nvme, nvme->n_intr_type, + nvme->n_ioq_count) != DDI_SUCCESS) { dev_err(nvme->n_dip, CE_WARN, "!failed to reduce number of interrupts"); goto fail; @@ -2171,6 +2185,7 @@ nvme_intr(caddr_t arg1, caddr_t arg2) /*LINTED: E_PTR_BAD_CAST_ALIGN*/ nvme_t *nvme = (nvme_t *)arg1; int inum = (int)(uintptr_t)arg2; + int ccnt = 0; int qnum; nvme_cmd_t *cmd; @@ -2188,10 +2203,11 @@ nvme_intr(caddr_t arg1, caddr_t arg2) while ((cmd = nvme_retrieve_cmd(nvme, nvme->n_ioq[qnum]))) { taskq_dispatch_ent((taskq_t *)cmd->nc_nvme->n_cmd_taskq, cmd->nc_callback, cmd, TQ_NOSLEEP, &cmd->nc_tqent); + ccnt++; } } - return (DDI_INTR_CLAIMED); + return (ccnt > 0 ? DDI_INTR_CLAIMED : DDI_INTR_UNCLAIMED); } static void @@ -2222,7 +2238,6 @@ nvme_release_interrupts(nvme_t *nvme) static int nvme_setup_interrupts(nvme_t *nvme, int intr_type, int nqpairs) { - int failed = 0; int nintrs, navail, count; int ret; int i; @@ -2292,25 +2307,18 @@ nvme_setup_interrupts(nvme_t *nvme, int intr_type, int nqpairs) (void) ddi_intr_get_cap(nvme->n_inth[0], &nvme->n_intr_cap); for (i = 0; i < count; i++) { - if (nvme->n_inth[i] == NULL) - break; + if (nvme->n_intr_cap & DDI_INTR_FLAG_BLOCK) + ret = ddi_intr_block_enable(&nvme->n_inth[i], 1); + else + ret = ddi_intr_enable(nvme->n_inth[i]); - if (nvme->n_intr_cap & DDI_INTR_FLAG_BLOCK) { - if (ddi_intr_block_enable(&nvme->n_inth[i], 1) != - DDI_SUCCESS) - failed++; - } else { - if (ddi_intr_enable(nvme->n_inth[i]) != DDI_SUCCESS) - failed++; + if (ret != DDI_SUCCESS) { + dev_err(nvme->n_dip, CE_WARN, + "!%s: enabling interrupt %d failed", __func__, i); + goto fail; } } - if (failed != 0) { - dev_err(nvme->n_dip, CE_WARN, - "!%s: enabling interrupts failed", __func__); - goto fail; - } - nvme->n_intr_type = intr_type; nvme->n_progress |= NVME_INTERRUPTS; diff --git a/usr/src/uts/common/io/nvme/nvme_var.h b/usr/src/uts/common/io/nvme/nvme_var.h index 8071da3872..f23e63b5db 100644 --- a/usr/src/uts/common/io/nvme/nvme_var.h +++ b/usr/src/uts/common/io/nvme/nvme_var.h @@ -10,7 +10,7 @@ */ /* - * Copyright 2015 Nexenta Systems, Inc. All rights reserved. + * Copyright 2016 Nexenta Systems, Inc. All rights reserved. */ #ifndef _NVME_VAR_H @@ -42,7 +42,6 @@ #define NVME_DEFAULT_ASYNC_EVENT_LIMIT 10 #define NVME_MIN_ASYNC_EVENT_LIMIT 1 -#define NVME_ADMIN_CMD_TIMEOUT 100000 typedef struct nvme nvme_t; typedef struct nvme_namespace nvme_namespace_t; diff --git a/usr/src/uts/common/io/sata/impl/sata.c b/usr/src/uts/common/io/sata/impl/sata.c index 66c141bf83..c4013d0efd 100644 --- a/usr/src/uts/common/io/sata/impl/sata.c +++ b/usr/src/uts/common/io/sata/impl/sata.c @@ -24,6 +24,7 @@ */ /* * Copyright 2015 Nexenta Systems, Inc. All rights reserved. + * Copyright 2016 Argo Technologies SA */ /* @@ -4516,6 +4517,7 @@ sata_txlt_read_capacity(sata_pkt_txlate_t *spx) struct buf *bp = spx->txlt_sata_pkt->satapkt_cmd.satacmd_bp; sata_drive_info_t *sdinfo; uint64_t val; + uint32_t lbsize = DEV_BSIZE; uchar_t *rbuf; int rval, reason; kmutex_t *cport_mutex = &(SATA_TXLT_CPORT_MUTEX(spx)); @@ -4554,17 +4556,28 @@ sata_txlt_read_capacity(sata_pkt_txlate_t *spx) */ val = MIN(sdinfo->satadrv_capacity - 1, UINT32_MAX); + 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_BIG_SECTORS) { + /* if this set 117-118 words are valid */ + lbsize = sdinfo->satadrv_id.ai_words_lsec[0] | + (sdinfo->satadrv_id.ai_words_lsec[1] << 16); + lbsize <<= 1; /* convert from words to bytes */ + } + } rbuf = (uchar_t *)bp->b_un.b_addr; /* Need to swap endians to match scsi format */ rbuf[0] = (val >> 24) & 0xff; rbuf[1] = (val >> 16) & 0xff; rbuf[2] = (val >> 8) & 0xff; rbuf[3] = val & 0xff; - /* block size - always 512 bytes, for now */ - rbuf[4] = 0; - rbuf[5] = 0; - rbuf[6] = 0x02; - rbuf[7] = 0; + rbuf[4] = (lbsize >> 24) & 0xff; + rbuf[5] = (lbsize >> 16) & 0xff; + rbuf[6] = (lbsize >> 8) & 0xff; + rbuf[7] = lbsize & 0xff; + scsipkt->pkt_state |= STATE_XFERRED_DATA; scsipkt->pkt_resid = 0; @@ -4614,6 +4627,7 @@ sata_txlt_read_capacity16(sata_pkt_txlate_t *spx) sata_drive_info_t *sdinfo; uint64_t val; uint16_t l2p_exp; + uint32_t lbsize = DEV_BSIZE; uchar_t *rbuf; int rval, reason; #define TPE 0x80 @@ -4697,6 +4711,14 @@ sata_txlt_read_capacity16(sata_pkt_txlate_t *spx) sdinfo->satadrv_id.ai_phys_sect_sz & SATA_L2PS_EXP_MASK; } + + if (sdinfo->satadrv_id.ai_phys_sect_sz & + SATA_L2PS_BIG_SECTORS) { + /* if this set 117-118 words are valid */ + lbsize = sdinfo->satadrv_id.ai_words_lsec[0] | + (sdinfo->satadrv_id.ai_words_lsec[1] << 16); + lbsize <<= 1; /* convert from words to bytes */ + } } rbuf = (uchar_t *)bp->b_un.b_addr; @@ -4711,12 +4733,10 @@ sata_txlt_read_capacity16(sata_pkt_txlate_t *spx) 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; */ + rbuf[8] = (lbsize >> 24) & 0xff; + rbuf[9] = (lbsize >> 16) & 0xff; + rbuf[10] = (lbsize >> 8) & 0xff; + rbuf[11] = lbsize & 0xff; /* p_type, prot_en, unspecified by SAT-2 */ /* rbuf[12] = 0; */ |