From owner-svn-src-head@freebsd.org Mon Sep 11 01:51:29 2017 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 96869E113F4; Mon, 11 Sep 2017 01:51:29 +0000 (UTC) (envelope-from scottl@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 6203F69FA2; Mon, 11 Sep 2017 01:51:29 +0000 (UTC) (envelope-from scottl@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id v8B1pSqt053956; Mon, 11 Sep 2017 01:51:28 GMT (envelope-from scottl@FreeBSD.org) Received: (from scottl@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id v8B1pRQR053947; Mon, 11 Sep 2017 01:51:27 GMT (envelope-from scottl@FreeBSD.org) Message-Id: <201709110151.v8B1pRQR053947@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: scottl set sender to scottl@FreeBSD.org using -f From: Scott Long Date: Mon, 11 Sep 2017 01:51:27 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r323412 - in head/sys/dev: mpr mps X-SVN-Group: head X-SVN-Commit-Author: scottl X-SVN-Commit-Paths: in head/sys/dev: mpr mps X-SVN-Commit-Revision: 323412 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 11 Sep 2017 01:51:29 -0000 Author: scottl Date: Mon Sep 11 01:51:27 2017 New Revision: 323412 URL: https://svnweb.freebsd.org/changeset/base/323412 Log: Add infrastructure for allocating multiple MSI-X interrupts. Also add more fine-tuned controls for allocating requests and replies. Sponsored by: Netflix Modified: head/sys/dev/mpr/mpr.c head/sys/dev/mpr/mpr_pci.c head/sys/dev/mpr/mpr_sas.c head/sys/dev/mpr/mprvar.h head/sys/dev/mps/mps.c head/sys/dev/mps/mps_pci.c head/sys/dev/mps/mps_sas.c head/sys/dev/mps/mpsvar.h Modified: head/sys/dev/mpr/mpr.c ============================================================================== --- head/sys/dev/mpr/mpr.c Mon Sep 11 01:26:26 2017 (r323411) +++ head/sys/dev/mpr/mpr.c Mon Sep 11 01:51:27 2017 (r323412) @@ -82,6 +82,7 @@ __FBSDID("$FreeBSD$"); static int mpr_diag_reset(struct mpr_softc *sc, int sleep_flag); static int mpr_init_queues(struct mpr_softc *sc); +static void mpr_resize_queues(struct mpr_softc *sc); static int mpr_message_unit_reset(struct mpr_softc *sc, int sleep_flag); static int mpr_transition_operational(struct mpr_softc *sc); static int mpr_iocfacts_allocate(struct mpr_softc *sc, uint8_t attaching); @@ -374,6 +375,46 @@ mpr_transition_operational(struct mpr_softc *sc) return (error); } +static void +mpr_resize_queues(struct mpr_softc *sc) +{ + int reqcr, prireqcr; + + /* + * Size the queues. Since the reply queues always need one free + * entry, we'll deduct one reply message here. The LSI documents + * suggest instead to add a count to the request queue, but I think + * that it's better to deduct from reply queue. + */ + prireqcr = MAX(1, sc->max_prireqframes); + prireqcr = MIN(prireqcr, sc->facts->HighPriorityCredit); + + reqcr = MAX(2, sc->max_reqframes); + reqcr = MIN(reqcr, sc->facts->RequestCredit); + + sc->num_reqs = prireqcr + reqcr; + sc->num_replies = MIN(sc->max_replyframes + sc->max_evtframes, + sc->facts->MaxReplyDescriptorPostQueueDepth) - 1; + + /* + * Figure out the number of MSIx-based queues. If the firmware or + * user has done something crazy and not allowed enough credit for + * the queues to be useful then don't enable multi-queue. + */ + if (sc->facts->MaxMSIxVectors < 2) + sc->msi_msgs = 1; + + if (sc->msi_msgs > 1) { + sc->msi_msgs = MIN(sc->msi_msgs, mp_ncpus); + sc->msi_msgs = MIN(sc->msi_msgs, sc->facts->MaxMSIxVectors); + if (sc->num_reqs / sc->msi_msgs < 2) + sc->msi_msgs = 1; + } + + mpr_dprint(sc, MPR_INIT, "Sized queues to q=%d reqs=%d replies=%d\n", + sc->msi_msgs, sc->num_reqs, sc->num_replies); +} + /* * This is called during attach and when re-initializing due to a Diag Reset. * IOC Facts is used to allocate many of the structures needed by the driver. @@ -530,13 +571,7 @@ mpr_iocfacts_allocate(struct mpr_softc *sc, uint8_t at MPI26_IOCFACTS_CAPABILITY_ATOMIC_REQ) sc->atomic_desc_capable = TRUE; - /* - * Size the queues. Since the reply queues always need one free - * entry, we'll just deduct one reply message here. - */ - sc->num_reqs = MIN(MPR_REQ_FRAMES, sc->facts->RequestCredit); - sc->num_replies = MIN(MPR_REPLY_FRAMES + MPR_EVT_REPLY_FRAMES, - sc->facts->MaxReplyDescriptorPostQueueDepth) - 1; + mpr_resize_queues(sc); /* * Initialize all Tail Queues @@ -1146,11 +1181,11 @@ mpr_alloc_queues(struct mpr_softc *sc) struct mpr_queue *q; int nq, i; - nq = MIN(sc->msi_msgs, mp_ncpus); - sc->msi_msgs = nq; + nq = sc->msi_msgs; mpr_dprint(sc, MPR_INIT|MPR_XINFO, "Allocating %d I/O queues\n", nq); - sc->queues = malloc(sizeof(struct mpr_queue) * nq, M_MPR, M_NOWAIT|M_ZERO); + sc->queues = malloc(sizeof(struct mpr_queue) * nq, M_MPR, + M_NOWAIT|M_ZERO); if (sc->queues == NULL) return (ENOMEM); @@ -1562,11 +1597,16 @@ mpr_get_tunables(struct mpr_softc *sc) sc->mpr_debug = MPR_INFO | MPR_FAULT; sc->disable_msix = 0; sc->disable_msi = 0; + sc->max_msix = MPR_MSIX_MAX; sc->max_chains = MPR_CHAIN_FRAMES; sc->max_io_pages = MPR_MAXIO_PAGES; sc->enable_ssu = MPR_SSU_ENABLE_SSD_DISABLE_HDD; sc->spinup_wait_time = DEFAULT_SPINUP_WAIT; sc->use_phynum = 1; + sc->max_reqframes = MPR_REQ_FRAMES; + sc->max_prireqframes = MPR_PRI_REQ_FRAMES; + sc->max_replyframes = MPR_REPLY_FRAMES; + sc->max_evtframes = MPR_EVT_REPLY_FRAMES; /* * Grab the global variables. @@ -1574,11 +1614,16 @@ mpr_get_tunables(struct mpr_softc *sc) TUNABLE_INT_FETCH("hw.mpr.debug_level", &sc->mpr_debug); TUNABLE_INT_FETCH("hw.mpr.disable_msix", &sc->disable_msix); TUNABLE_INT_FETCH("hw.mpr.disable_msi", &sc->disable_msi); + TUNABLE_INT_FETCH("hw.mpr.max_msix", &sc->max_msix); TUNABLE_INT_FETCH("hw.mpr.max_chains", &sc->max_chains); TUNABLE_INT_FETCH("hw.mpr.max_io_pages", &sc->max_io_pages); TUNABLE_INT_FETCH("hw.mpr.enable_ssu", &sc->enable_ssu); TUNABLE_INT_FETCH("hw.mpr.spinup_wait_time", &sc->spinup_wait_time); TUNABLE_INT_FETCH("hw.mpr.use_phy_num", &sc->use_phynum); + TUNABLE_INT_FETCH("hw.mpr.max_reqframes", &sc->max_reqframes); + TUNABLE_INT_FETCH("hw.mpr.max_prireqframes", &sc->max_prireqframes); + TUNABLE_INT_FETCH("hw.mpr.max_replyframes", &sc->max_replyframes); + TUNABLE_INT_FETCH("hw.mpr.max_evtframes", &sc->max_evtframes); /* Grab the unit-instance variables */ snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.debug_level", @@ -1593,6 +1638,10 @@ mpr_get_tunables(struct mpr_softc *sc) device_get_unit(sc->mpr_dev)); TUNABLE_INT_FETCH(tmpstr, &sc->disable_msi); + snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.max_msix", + device_get_unit(sc->mpr_dev)); + TUNABLE_INT_FETCH(tmpstr, &sc->max_msix); + snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.max_chains", device_get_unit(sc->mpr_dev)); TUNABLE_INT_FETCH(tmpstr, &sc->max_chains); @@ -1617,6 +1666,22 @@ mpr_get_tunables(struct mpr_softc *sc) snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.use_phy_num", device_get_unit(sc->mpr_dev)); TUNABLE_INT_FETCH(tmpstr, &sc->use_phynum); + + snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.max_reqframes", + device_get_unit(sc->mpr_dev)); + TUNABLE_INT_FETCH(tmpstr, &sc->max_reqframes); + + snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.max_prireqframes", + device_get_unit(sc->mpr_dev)); + TUNABLE_INT_FETCH(tmpstr, &sc->max_prireqframes); + + snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.max_replyframes", + device_get_unit(sc->mpr_dev)); + TUNABLE_INT_FETCH(tmpstr, &sc->max_replyframes); + + snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.max_evtframes", + device_get_unit(sc->mpr_dev)); + TUNABLE_INT_FETCH(tmpstr, &sc->max_evtframes); } static void @@ -1658,8 +1723,28 @@ mpr_setup_sysctl(struct mpr_softc *sc) "Disable the use of MSI-X interrupts"); SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), - OID_AUTO, "disable_msi", CTLFLAG_RD, &sc->disable_msi, 0, - "Disable the use of MSI interrupts"); + OID_AUTO, "max_msix", CTLFLAG_RD, &sc->max_msix, 0, + "User-defined maximum number of MSIX queues"); + + SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "msix_msgs", CTLFLAG_RD, &sc->msi_msgs, 0, + "Negotiated number of MSIX queues"); + + SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "max_reqframes", CTLFLAG_RD, &sc->max_reqframes, 0, + "Total number of allocated request frames"); + + SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "max_prireqframes", CTLFLAG_RD, &sc->max_prireqframes, 0, + "Total number of allocated high priority request frames"); + + SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "max_replyframes", CTLFLAG_RD, &sc->max_replyframes, 0, + "Total number of allocated reply frames"); + + SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "max_evtframes", CTLFLAG_RD, &sc->max_evtframes, 0, + "Total number of event frames allocated"); SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO, "firmware_version", CTLFLAG_RW, sc->fw_version, Modified: head/sys/dev/mpr/mpr_pci.c ============================================================================== --- head/sys/dev/mpr/mpr_pci.c Mon Sep 11 01:26:26 2017 (r323411) +++ head/sys/dev/mpr/mpr_pci.c Mon Sep 11 01:51:27 2017 (r323412) @@ -262,23 +262,38 @@ mpr_pci_alloc_interrupts(struct mpr_softc *sc) error = 0; msgs = 0; - if ((sc->disable_msix == 0) && - ((msgs = pci_msix_count(dev)) >= MPR_MSI_COUNT)) - error = mpr_alloc_msix(sc, MPR_MSI_COUNT); - if ((error != 0) && (sc->disable_msi == 0) && - ((msgs = pci_msi_count(dev)) >= MPR_MSI_COUNT)) - error = mpr_alloc_msi(sc, MPR_MSI_COUNT); - if (error != 0) { + if (sc->disable_msix == 0) { + msgs = pci_msix_count(dev); + mpr_dprint(sc, MPR_INIT, "Counted %d MSI-X messages\n", msgs); + msgs = min(msgs, sc->max_msix); + msgs = min(msgs, MPR_MSIX_MAX); + msgs = min(msgs, 1); /* XXX */ + if (msgs != 0) { + mpr_dprint(sc, MPR_INIT, "Attempting to allocate %d MSI-X " + "messages\n", msgs); + error = mpr_alloc_msix(sc, msgs); + } + } + if (((error != 0) || (msgs == 0)) && (sc->disable_msi == 0)) { + msgs = pci_msi_count(dev); + mpr_dprint(sc, MPR_INIT, "Counted %d MSI messages\n", msgs); + msgs = min(msgs, MPR_MSI_MAX); + if (msgs != 0) { + mpr_dprint(sc, MPR_INIT, "Attempting to allocated %d MSI " + "messages\n", MPR_MSI_MAX); + error = mpr_alloc_msi(sc, MPR_MSI_MAX); + } + } + if ((error != 0) || (msgs == 0)) { /* * If neither MSI or MSI-X are available, assume legacy INTx. * This also implies that there will be only 1 queue. */ + mpr_dprint(sc, MPR_INIT, "Falling back to legacy INTx\n"); sc->mpr_flags |= MPR_FLAGS_INTX; msgs = 1; - } else { + } else sc->mpr_flags |= MPR_FLAGS_MSI; - msgs = MPR_MSI_COUNT; /* XXX */ - } sc->msi_msgs = msgs; mpr_dprint(sc, MPR_INIT, "Allocated %d interrupts\n", msgs); @@ -318,6 +333,7 @@ mpr_pci_setup_interrupts(struct mpr_softc *sc) if (q->irq == NULL) { mpr_dprint(sc, MPR_ERROR|MPR_INIT, "Cannot allocate interrupt RID %d\n", rid); + sc->msi_msgs = i; break; } error = bus_setup_intr(dev, q->irq, @@ -326,6 +342,7 @@ mpr_pci_setup_interrupts(struct mpr_softc *sc) if (error) { mpr_dprint(sc, MPR_ERROR|MPR_INIT, "Cannot setup interrupt RID %d\n", rid); + sc->msi_msgs = i; break; } } Modified: head/sys/dev/mpr/mpr_sas.c ============================================================================== --- head/sys/dev/mpr/mpr_sas.c Mon Sep 11 01:26:26 2017 (r323411) +++ head/sys/dev/mpr/mpr_sas.c Mon Sep 11 01:51:27 2017 (r323412) @@ -924,6 +924,9 @@ mpr_detach_sas(struct mpr_softc *sc) /* Make sure CAM doesn't wedge if we had to bail out early. */ mpr_lock(sc); + while (sassc->startup_refcount != 0) + mprsas_startup_decrement(sassc); + /* Deregister our async handler */ if (sassc->path != NULL) { xpt_register_async(0, mprsas_async, sc, sassc->path); Modified: head/sys/dev/mpr/mprvar.h ============================================================================== --- head/sys/dev/mpr/mprvar.h Mon Sep 11 01:26:26 2017 (r323411) +++ head/sys/dev/mpr/mprvar.h Mon Sep 11 01:51:27 2017 (r323412) @@ -37,13 +37,15 @@ #define MPR_DB_MAX_WAIT 2500 -#define MPR_REQ_FRAMES 1024 +#define MPR_REQ_FRAMES 2048 +#define MPR_PRI_REQ_FRAMES 128 #define MPR_EVT_REPLY_FRAMES 32 #define MPR_REPLY_FRAMES MPR_REQ_FRAMES #define MPR_CHAIN_FRAMES 2048 #define MPR_MAXIO_PAGES (-1) #define MPR_SENSE_LEN SSD_FULL_SIZE -#define MPR_MSI_COUNT 1 +#define MPR_MSI_MAX 1 +#define MPR_MSIX_MAX 96 #define MPR_SGE64_SIZE 12 #define MPR_SGE32_SIZE 8 #define MPR_SGC_SIZE 8 @@ -296,8 +298,6 @@ struct mpr_softc { #define MPR_FLAGS_GEN35_IOC (1 << 6) #define MPR_FLAGS_REALLOCATED (1 << 7) u_int mpr_debug; - u_int disable_msix; - u_int disable_msi; int msi_msgs; u_int atomic_desc_capable; int tm_cmds_active; @@ -446,7 +446,16 @@ struct mpr_softc { uint32_t SSU_refcount; uint8_t SSU_started; + /* Configuration tunables */ + u_int disable_msix; + u_int disable_msi; + u_int max_msix; + u_int max_reqframes; + u_int max_prireqframes; + u_int max_replyframes; + u_int max_evtframes; char exclude_ids[80]; + struct timeval lastfail; }; Modified: head/sys/dev/mps/mps.c ============================================================================== --- head/sys/dev/mps/mps.c Mon Sep 11 01:26:26 2017 (r323411) +++ head/sys/dev/mps/mps.c Mon Sep 11 01:51:27 2017 (r323412) @@ -80,6 +80,7 @@ __FBSDID("$FreeBSD$"); static int mps_diag_reset(struct mps_softc *sc, int sleep_flag); static int mps_init_queues(struct mps_softc *sc); +static void mps_resize_queues(struct mps_softc *sc); static int mps_message_unit_reset(struct mps_softc *sc, int sleep_flag); static int mps_transition_operational(struct mps_softc *sc); static int mps_iocfacts_allocate(struct mps_softc *sc, uint8_t attaching); @@ -368,6 +369,46 @@ mps_transition_operational(struct mps_softc *sc) return (error); } +static void +mps_resize_queues(struct mps_softc *sc) +{ + int reqcr, prireqcr; + + /* + * Size the queues. Since the reply queues always need one free + * entry, we'll deduct one reply message here. The LSI documents + * suggest instead to add a count to the request queue, but I think + * that it's better to deduct from reply queue. + */ + prireqcr = MAX(1, sc->max_prireqframes); + prireqcr = MIN(prireqcr, sc->facts->HighPriorityCredit); + + reqcr = MAX(2, sc->max_reqframes); + reqcr = MIN(reqcr, sc->facts->RequestCredit); + + sc->num_reqs = prireqcr + reqcr; + sc->num_replies = MIN(sc->max_replyframes + sc->max_evtframes, + sc->facts->MaxReplyDescriptorPostQueueDepth) - 1; + + /* + * Figure out the number of MSIx-based queues. If the firmware or + * user has done something crazy and not allowed enough credit for + * the queues to be useful then don't enable multi-queue. + */ + if (sc->facts->MaxMSIxVectors < 2) + sc->msi_msgs = 1; + + if (sc->msi_msgs > 1) { + sc->msi_msgs = MIN(sc->msi_msgs, mp_ncpus); + sc->msi_msgs = MIN(sc->msi_msgs, sc->facts->MaxMSIxVectors); + if (sc->num_reqs / sc->msi_msgs < 2) + sc->msi_msgs = 1; + } + + mps_dprint(sc, MPS_INIT, "Sized queues to q=%d reqs=%d replies=%d\n", + sc->msi_msgs, sc->num_reqs, sc->num_replies); +} + /* * This is called during attach and when re-initializing due to a Diag Reset. * IOC Facts is used to allocate many of the structures needed by the driver. @@ -518,13 +559,7 @@ mps_iocfacts_allocate(struct mps_softc *sc, uint8_t at if (sc->facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR) sc->control_TLR = TRUE; - /* - * Size the queues. Since the reply queues always need one free - * entry, we'll just deduct one reply message here. - */ - sc->num_reqs = MIN(MPS_REQ_FRAMES, sc->facts->RequestCredit); - sc->num_replies = MIN(MPS_REPLY_FRAMES + MPS_EVT_REPLY_FRAMES, - sc->facts->MaxReplyDescriptorPostQueueDepth) - 1; + mps_resize_queues(sc); /* * Initialize all Tail Queues @@ -1121,11 +1156,11 @@ mps_alloc_queues(struct mps_softc *sc) struct mps_queue *q; int nq, i; - nq = MIN(sc->msi_msgs, mp_ncpus); - sc->msi_msgs = nq; + nq = sc->msi_msgs; mps_dprint(sc, MPS_INIT|MPS_XINFO, "Allocating %d I/O queues\n", nq); - sc->queues = malloc(sizeof(struct mps_queue) * nq, M_MPT2, M_NOWAIT|M_ZERO); + sc->queues = malloc(sizeof(struct mps_queue) * nq, M_MPT2, + M_NOWAIT|M_ZERO); if (sc->queues == NULL) return (ENOMEM); @@ -1423,11 +1458,16 @@ mps_get_tunables(struct mps_softc *sc) sc->mps_debug = MPS_INFO|MPS_FAULT; sc->disable_msix = 0; sc->disable_msi = 0; + sc->max_msix = MPS_MSIX_MAX; sc->max_chains = MPS_CHAIN_FRAMES; sc->max_io_pages = MPS_MAXIO_PAGES; sc->enable_ssu = MPS_SSU_ENABLE_SSD_DISABLE_HDD; sc->spinup_wait_time = DEFAULT_SPINUP_WAIT; sc->use_phynum = 1; + sc->max_reqframes = MPS_REQ_FRAMES; + sc->max_prireqframes = MPS_PRI_REQ_FRAMES; + sc->max_replyframes = MPS_REPLY_FRAMES; + sc->max_evtframes = MPS_EVT_REPLY_FRAMES; /* * Grab the global variables. @@ -1435,11 +1475,16 @@ mps_get_tunables(struct mps_softc *sc) TUNABLE_INT_FETCH("hw.mps.debug_level", &sc->mps_debug); TUNABLE_INT_FETCH("hw.mps.disable_msix", &sc->disable_msix); TUNABLE_INT_FETCH("hw.mps.disable_msi", &sc->disable_msi); + TUNABLE_INT_FETCH("hw.mps.max_msix", &sc->max_msix); TUNABLE_INT_FETCH("hw.mps.max_chains", &sc->max_chains); TUNABLE_INT_FETCH("hw.mps.max_io_pages", &sc->max_io_pages); TUNABLE_INT_FETCH("hw.mps.enable_ssu", &sc->enable_ssu); TUNABLE_INT_FETCH("hw.mps.spinup_wait_time", &sc->spinup_wait_time); TUNABLE_INT_FETCH("hw.mps.use_phy_num", &sc->use_phynum); + TUNABLE_INT_FETCH("hw.mps.max_reqframes", &sc->max_reqframes); + TUNABLE_INT_FETCH("hw.mps.max_prireqframes", &sc->max_prireqframes); + TUNABLE_INT_FETCH("hw.mps.max_replyframes", &sc->max_replyframes); + TUNABLE_INT_FETCH("hw.mps.max_evtframes", &sc->max_evtframes); /* Grab the unit-instance variables */ snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.debug_level", @@ -1454,6 +1499,10 @@ mps_get_tunables(struct mps_softc *sc) device_get_unit(sc->mps_dev)); TUNABLE_INT_FETCH(tmpstr, &sc->disable_msi); + snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.max_msix", + device_get_unit(sc->mps_dev)); + TUNABLE_INT_FETCH(tmpstr, &sc->max_msix); + snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.max_chains", device_get_unit(sc->mps_dev)); TUNABLE_INT_FETCH(tmpstr, &sc->max_chains); @@ -1478,6 +1527,23 @@ mps_get_tunables(struct mps_softc *sc) snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.use_phy_num", device_get_unit(sc->mps_dev)); TUNABLE_INT_FETCH(tmpstr, &sc->use_phynum); + + snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.max_reqframes", + device_get_unit(sc->mps_dev)); + TUNABLE_INT_FETCH(tmpstr, &sc->max_reqframes); + + snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.max_prireqframes", + device_get_unit(sc->mps_dev)); + TUNABLE_INT_FETCH(tmpstr, &sc->max_prireqframes); + + snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.max_replyframes", + device_get_unit(sc->mps_dev)); + TUNABLE_INT_FETCH(tmpstr, &sc->max_replyframes); + + snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.max_evtframes", + device_get_unit(sc->mps_dev)); + TUNABLE_INT_FETCH(tmpstr, &sc->max_evtframes); + } static void @@ -1521,6 +1587,30 @@ mps_setup_sysctl(struct mps_softc *sc) SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO, "disable_msi", CTLFLAG_RD, &sc->disable_msi, 0, "Disable the use of MSI interrupts"); + + SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "max_msix", CTLFLAG_RD, &sc->max_msix, 0, + "User-defined maximum number of MSIX queues"); + + SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "msix_msgs", CTLFLAG_RD, &sc->msi_msgs, 0, + "Negotiated number of MSIX queues"); + + SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "max_reqframes", CTLFLAG_RD, &sc->max_reqframes, 0, + "Total number of allocated request frames"); + + SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "max_prireqframes", CTLFLAG_RD, &sc->max_prireqframes, 0, + "Total number of allocated high priority request frames"); + + SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "max_replyframes", CTLFLAG_RD, &sc->max_replyframes, 0, + "Total number of allocated reply frames"); + + SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "max_evtframes", CTLFLAG_RD, &sc->max_evtframes, 0, + "Total number of event frames allocated"); SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO, "firmware_version", CTLFLAG_RW, sc->fw_version, Modified: head/sys/dev/mps/mps_pci.c ============================================================================== --- head/sys/dev/mps/mps_pci.c Mon Sep 11 01:26:26 2017 (r323411) +++ head/sys/dev/mps/mps_pci.c Mon Sep 11 01:51:27 2017 (r323412) @@ -247,23 +247,38 @@ mps_pci_alloc_interrupts(struct mps_softc *sc) error = 0; msgs = 0; - if ((sc->disable_msix == 0) && - ((msgs = pci_msix_count(dev)) >= MPS_MSI_COUNT)) - error = mps_alloc_msix(sc, MPS_MSI_COUNT); - if ((error != 0) && (sc->disable_msi == 0) && - ((msgs = pci_msi_count(dev)) >= MPS_MSI_COUNT)) - error = mps_alloc_msi(sc, MPS_MSI_COUNT); - if (error != 0) { + if (sc->disable_msix == 0) { + msgs = pci_msix_count(dev); + mps_dprint(sc, MPS_INIT, "Counted %d MSI-X messages\n", msgs); + msgs = min(msgs, sc->max_msix); + msgs = min(msgs, MPS_MSIX_MAX); + msgs = min(msgs, 1); /* XXX */ + if (msgs != 0) { + mps_dprint(sc, MPS_INIT, "Attempting to allocate %d MSI-X " + "messages\n", msgs); + error = mps_alloc_msix(sc, msgs); + } + } + if (((error != 0) || (msgs == 0)) && (sc->disable_msi == 0)) { + msgs = pci_msi_count(dev); + mps_dprint(sc, MPS_INIT, "Counted %d MSI messages\n", msgs); + msgs = min(msgs, MPS_MSI_MAX); + if (msgs != 0) { + mps_dprint(sc, MPS_INIT, "Attempting to allocate %d MSI " + "messages\n", MPS_MSI_MAX); + error = mps_alloc_msi(sc, MPS_MSI_MAX); + } + } + if ((error != 0) || (msgs == 0)) { /* * If neither MSI or MSI-X are avaiable, assume legacy INTx. * This also implies that there will be only 1 queue. */ + mps_dprint(sc, MPS_INIT, "Falling back to legacy INTx\n"); sc->mps_flags |= MPS_FLAGS_INTX; msgs = 1; - } else { + } else sc->mps_flags |= MPS_FLAGS_MSI; - msgs = 1; /* XXX */ - } sc->msi_msgs = msgs; mps_dprint(sc, MPS_INIT, "Allocated %d interrupts\n", msgs); @@ -302,7 +317,8 @@ mps_pci_setup_interrupts(struct mps_softc *sc) &q->irq_rid, RF_ACTIVE); if (q->irq == NULL) { mps_dprint(sc, MPS_ERROR|MPS_INIT, - "Cannot allocate interrupt RID%d\n", rid); + "Cannot allocate interrupt RID %d\n", rid); + sc->msi_msgs = i; break; } error = bus_setup_intr(dev, q->irq, @@ -311,6 +327,7 @@ mps_pci_setup_interrupts(struct mps_softc *sc) if (error) { mps_dprint(sc, MPS_ERROR|MPS_INIT, "Cannot setup interrupt RID %d\n", rid); + sc->msi_msgs = i; break; } } Modified: head/sys/dev/mps/mps_sas.c ============================================================================== --- head/sys/dev/mps/mps_sas.c Mon Sep 11 01:26:26 2017 (r323411) +++ head/sys/dev/mps/mps_sas.c Mon Sep 11 01:51:27 2017 (r323412) @@ -871,6 +871,9 @@ mps_detach_sas(struct mps_softc *sc) /* Make sure CAM doesn't wedge if we had to bail out early. */ mps_lock(sc); + while (sassc->startup_refcount != 0) + mpssas_startup_decrement(sassc); + /* Deregister our async handler */ if (sassc->path != NULL) { xpt_register_async(0, mpssas_async, sc, sassc->path); Modified: head/sys/dev/mps/mpsvar.h ============================================================================== --- head/sys/dev/mps/mpsvar.h Mon Sep 11 01:26:26 2017 (r323411) +++ head/sys/dev/mps/mpsvar.h Mon Sep 11 01:51:27 2017 (r323412) @@ -37,13 +37,15 @@ #define MPS_DB_MAX_WAIT 2500 -#define MPS_REQ_FRAMES 1024 +#define MPS_REQ_FRAMES 2048 +#define MPS_PRI_REQ_FRAMES 128 #define MPS_EVT_REPLY_FRAMES 32 #define MPS_REPLY_FRAMES MPS_REQ_FRAMES #define MPS_CHAIN_FRAMES 2048 #define MPS_MAXIO_PAGES (-1) #define MPS_SENSE_LEN SSD_FULL_SIZE -#define MPS_MSI_COUNT 1 +#define MPS_MSI_MAX 1 +#define MPS_MSIX_MAX 16 #define MPS_SGE64_SIZE 12 #define MPS_SGE32_SIZE 8 #define MPS_SGC_SIZE 8 @@ -292,8 +294,6 @@ struct mps_softc { #define MPS_FLAGS_WD_AVAILABLE (1 << 6) #define MPS_FLAGS_REALLOCATED (1 << 7) u_int mps_debug; - u_int disable_msix; - u_int disable_msi; u_int msi_msgs; int tm_cmds_active; int io_cmds_active; @@ -437,12 +437,21 @@ struct mps_softc { uint64_t DD_max_lba; struct mps_column_map DD_column_map[MPS_MAX_DISKS_IN_VOL]; - char exclude_ids[80]; - struct timeval lastfail; - /* StartStopUnit command handling at shutdown */ uint32_t SSU_refcount; uint8_t SSU_started; + + /* Configuration tunables */ + u_int disable_msix; + u_int disable_msi; + u_int max_msix; + u_int max_reqframes; + u_int max_prireqframes; + u_int max_replyframes; + u_int max_evtframes; + char exclude_ids[80]; + + struct timeval lastfail; }; struct mps_config_params {