Index: head/sys/dev/mpr/mpr.c =================================================================== --- head/sys/dev/mpr/mpr.c +++ head/sys/dev/mpr/mpr.c @@ -382,7 +382,7 @@ static void mpr_resize_queues(struct mpr_softc *sc) { - int reqcr, prireqcr; + u_int reqcr, prireqcr, maxio, sges_per_frame; /* * Size the queues. Since the reply queues always need one free @@ -401,7 +401,61 @@ sc->num_replies = MIN(sc->max_replyframes + sc->max_evtframes, sc->facts->MaxReplyDescriptorPostQueueDepth) - 1; + /* Store the request frame size in bytes rather than as 32bit words */ + sc->reqframesz = sc->facts->IOCRequestFrameSize * 4; + /* + * Gen3 and beyond uses the IOCMaxChainSegmentSize from IOC Facts to + * get the size of a Chain Frame. Previous versions use the size as a + * Request Frame for the Chain Frame size. If IOCMaxChainSegmentSize + * is 0, use the default value. The IOCMaxChainSegmentSize is the + * number of 16-byte elelements that can fit in a Chain Frame, which is + * the size of an IEEE Simple SGE. + */ + if (sc->facts->MsgVersion >= MPI2_VERSION_02_05) { + sc->chain_seg_size = + htole16(sc->facts->IOCMaxChainSegmentSize); + if (sc->chain_seg_size == 0) { + sc->chain_frame_size = MPR_DEFAULT_CHAIN_SEG_SIZE * + MPR_MAX_CHAIN_ELEMENT_SIZE; + } else { + sc->chain_frame_size = sc->chain_seg_size * + MPR_MAX_CHAIN_ELEMENT_SIZE; + } + } else { + sc->chain_frame_size = sc->reqframesz; + } + + /* + * Max IO Size is Page Size * the following: + * ((SGEs per frame - 1 for chain element) * Max Chain Depth) + * + 1 for no chain needed in last frame + * + * If user suggests a Max IO size to use, use the smaller of the + * user's value and the calculated value as long as the user's + * value is larger than 0. The user's value is in pages. + */ + sges_per_frame = sc->chain_frame_size/sizeof(MPI2_IEEE_SGE_SIMPLE64)-1; + maxio = (sges_per_frame * sc->facts->MaxChainDepth + 1) * PAGE_SIZE; + + /* + * If I/O size limitation requested then use it and pass up to CAM. + * If not, use MAXPHYS as an optimization hint, but report HW limit. + */ + if (sc->max_io_pages > 0) { + maxio = min(maxio, sc->max_io_pages * PAGE_SIZE); + sc->maxio = maxio; + } else { + sc->maxio = maxio; + maxio = min(maxio, MAXPHYS); + } + + sc->num_chains = (maxio / PAGE_SIZE + sges_per_frame - 2) / + sges_per_frame * reqcr; + if (sc->max_chains > 0 && sc->max_chains < sc->num_chains) + sc->num_chains = sc->max_chains; + + /* * 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. @@ -1355,9 +1409,6 @@ struct mpr_chain *chain; int i, rsize, nsegs; - /* Store the request frame size in bytes rather than as 32bit words */ - sc->reqframesz = sc->facts->IOCRequestFrameSize * 4; - rsize = sc->reqframesz * sc->num_reqs; if (bus_dma_tag_create( sc->mpr_parent_dmat, /* parent */ 16, 0, /* algnmnt, boundary */ @@ -1382,28 +1433,7 @@ bus_dmamap_load(sc->req_dmat, sc->req_map, sc->req_frames, rsize, mpr_memaddr_cb, &sc->req_busaddr, 0); - /* - * Gen3 and beyond uses the IOCMaxChainSegmentSize from IOC Facts to - * get the size of a Chain Frame. Previous versions use the size as a - * Request Frame for the Chain Frame size. If IOCMaxChainSegmentSize - * is 0, use the default value. The IOCMaxChainSegmentSize is the - * number of 16-byte elelements that can fit in a Chain Frame, which is - * the size of an IEEE Simple SGE. - */ - if (sc->facts->MsgVersion >= MPI2_VERSION_02_05) { - sc->chain_seg_size = - htole16(sc->facts->IOCMaxChainSegmentSize); - if (sc->chain_seg_size == 0) { - sc->chain_frame_size = MPR_DEFAULT_CHAIN_SEG_SIZE * - MPR_MAX_CHAIN_ELEMENT_SIZE; - } else { - sc->chain_frame_size = sc->chain_seg_size * - MPR_MAX_CHAIN_ELEMENT_SIZE; - } - } else { - sc->chain_frame_size = sc->reqframesz; - } - rsize = sc->chain_frame_size * sc->max_chains; + rsize = sc->chain_frame_size * sc->num_chains; if (bus_dma_tag_create( sc->mpr_parent_dmat, /* parent */ 16, 0, /* algnmnt, boundary */ BUS_SPACE_MAXADDR, /* lowaddr */ @@ -1451,13 +1481,13 @@ bus_dmamap_load(sc->sense_dmat, sc->sense_map, sc->sense_frames, rsize, mpr_memaddr_cb, &sc->sense_busaddr, 0); - sc->chains = malloc(sizeof(struct mpr_chain) * sc->max_chains, M_MPR, + sc->chains = malloc(sizeof(struct mpr_chain) * sc->num_chains, M_MPR, M_WAITOK | M_ZERO); if (!sc->chains) { mpr_dprint(sc, MPR_ERROR, "Cannot allocate chain memory\n"); return (ENOMEM); } - for (i = 0; i < sc->max_chains; i++) { + for (i = 0; i < sc->num_chains; i++) { chain = &sc->chains[i]; chain->chain = (MPI2_SGE_IO_UNION *)(sc->chain_frames + i * sc->chain_frame_size); @@ -1477,8 +1507,7 @@ return (ENOMEM); } - /* XXX Need to pick a more precise value */ - nsegs = (MAXPHYS / PAGE_SIZE) + 1; + nsegs = (sc->maxio / PAGE_SIZE) + 1; if (bus_dma_tag_create( sc->mpr_parent_dmat, /* parent */ 1, 0, /* algnmnt, boundary */ BUS_SPACE_MAXADDR, /* lowaddr */ Index: head/sys/dev/mpr/mpr_sas.c =================================================================== --- head/sys/dev/mpr/mpr_sas.c +++ head/sys/dev/mpr/mpr_sas.c @@ -1009,7 +1009,6 @@ { struct ccb_pathinq *cpi = &ccb->cpi; struct mpr_softc *sc = sassc->sc; - uint8_t sges_per_frame; cpi->version_num = 1; cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16; @@ -1043,24 +1042,7 @@ cpi->transport_version = 0; cpi->protocol = PROTO_SCSI; cpi->protocol_version = SCSI_REV_SPC; - - /* - * Max IO Size is Page Size * the following: - * ((SGEs per frame - 1 for chain element) * - * Max Chain Depth) + 1 for no chain needed in last frame - * - * If user suggests a Max IO size to use, use the smaller of the - * user's value and the calculated value as long as the user's - * value is larger than 0. The user's value is in pages. - */ - sges_per_frame = (sc->chain_frame_size / - sizeof(MPI2_IEEE_SGE_SIMPLE64)) - 1; - cpi->maxio = (sges_per_frame * sc->facts->MaxChainDepth) + 1; - cpi->maxio *= PAGE_SIZE; - if ((sc->max_io_pages > 0) && (sc->max_io_pages * PAGE_SIZE < - cpi->maxio)) - cpi->maxio = sc->max_io_pages * PAGE_SIZE; - sc->maxio = cpi->maxio; + cpi->maxio = sc->maxio; mprsas_set_ccbstatus(ccb, CAM_REQ_CMP); break; } Index: head/sys/dev/mpr/mprvar.h =================================================================== --- head/sys/dev/mpr/mprvar.h +++ head/sys/dev/mpr/mprvar.h @@ -361,6 +361,7 @@ int num_reqs; int num_prireqs; int num_replies; + int num_chains; int fqdepth; /* Free queue */ int pqdepth; /* Post queue */ Index: head/sys/dev/mps/mps.c =================================================================== --- head/sys/dev/mps/mps.c +++ head/sys/dev/mps/mps.c @@ -379,8 +379,8 @@ static void mps_resize_queues(struct mps_softc *sc) { - int reqcr, prireqcr; - + u_int reqcr, prireqcr, maxio, sges_per_frame; + /* * Size the queues. Since the reply queues always need one free * entry, we'll deduct one reply message here. The LSI documents @@ -398,7 +398,39 @@ sc->num_replies = MIN(sc->max_replyframes + sc->max_evtframes, sc->facts->MaxReplyDescriptorPostQueueDepth) - 1; + /* Store the request frame size in bytes rather than as 32bit words */ + sc->reqframesz = sc->facts->IOCRequestFrameSize * 4; + /* + * Max IO Size is Page Size * the following: + * ((SGEs per frame - 1 for chain element) * Max Chain Depth) + * + 1 for no chain needed in last frame + * + * If user suggests a Max IO size to use, use the smaller of the + * user's value and the calculated value as long as the user's + * value is larger than 0. The user's value is in pages. + */ + sges_per_frame = sc->reqframesz / sizeof(MPI2_SGE_SIMPLE64) - 1; + maxio = (sges_per_frame * sc->facts->MaxChainDepth + 1) * PAGE_SIZE; + + /* + * If I/O size limitation requested, then use it and pass up to CAM. + * If not, use MAXPHYS as an optimization hint, but report HW limit. + */ + if (sc->max_io_pages > 0) { + maxio = min(maxio, sc->max_io_pages * PAGE_SIZE); + sc->maxio = maxio; + } else { + sc->maxio = maxio; + maxio = min(maxio, MAXPHYS); + } + + sc->num_chains = (maxio / PAGE_SIZE + sges_per_frame - 2) / + sges_per_frame * reqcr; + if (sc->max_chains > 0 && sc->max_chains < sc->num_chains) + sc->num_chains = sc->max_chains; + + /* * 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. @@ -1334,9 +1366,6 @@ struct mps_chain *chain; int i, rsize, nsegs; - /* Store the request frame size in bytes rather than as 32bit words */ - sc->reqframesz = sc->facts->IOCRequestFrameSize * 4; - rsize = sc->reqframesz * sc->num_reqs; if (bus_dma_tag_create( sc->mps_parent_dmat, /* parent */ 16, 0, /* algnmnt, boundary */ @@ -1361,7 +1390,7 @@ bus_dmamap_load(sc->req_dmat, sc->req_map, sc->req_frames, rsize, mps_memaddr_cb, &sc->req_busaddr, 0); - rsize = sc->reqframesz * sc->max_chains; + rsize = sc->reqframesz * sc->num_chains; if (bus_dma_tag_create( sc->mps_parent_dmat, /* parent */ 16, 0, /* algnmnt, boundary */ BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ @@ -1409,13 +1438,13 @@ bus_dmamap_load(sc->sense_dmat, sc->sense_map, sc->sense_frames, rsize, mps_memaddr_cb, &sc->sense_busaddr, 0); - sc->chains = malloc(sizeof(struct mps_chain) * sc->max_chains, M_MPT2, + sc->chains = malloc(sizeof(struct mps_chain) * sc->num_chains, M_MPT2, M_WAITOK | M_ZERO); if(!sc->chains) { mps_dprint(sc, MPS_ERROR, "Cannot allocate chains memory\n"); return (ENOMEM); } - for (i = 0; i < sc->max_chains; i++) { + for (i = 0; i < sc->num_chains; i++) { chain = &sc->chains[i]; chain->chain = (MPI2_SGE_IO_UNION *)(sc->chain_frames + i * sc->reqframesz); @@ -1425,8 +1454,7 @@ sc->chain_free_lowwater++; } - /* XXX Need to pick a more precise value */ - nsegs = (MAXPHYS / PAGE_SIZE) + 1; + nsegs = (sc->maxio / PAGE_SIZE) + 1; if (bus_dma_tag_create( sc->mps_parent_dmat, /* parent */ 1, 0, /* algnmnt, boundary */ BUS_SPACE_MAXADDR, /* lowaddr */ Index: head/sys/dev/mps/mps_sas.c =================================================================== --- head/sys/dev/mps/mps_sas.c +++ head/sys/dev/mps/mps_sas.c @@ -958,7 +958,6 @@ { struct ccb_pathinq *cpi = &ccb->cpi; struct mps_softc *sc = sassc->sc; - uint8_t sges_per_frame; cpi->version_num = 1; cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16; @@ -987,23 +986,7 @@ cpi->transport_version = 0; cpi->protocol = PROTO_SCSI; cpi->protocol_version = SCSI_REV_SPC; - - /* - * Max IO Size is Page Size * the following: - * ((SGEs per frame - 1 for chain element) * - * Max Chain Depth) + 1 for no chain needed in last frame - * - * If user suggests a Max IO size to use, use the smaller of the - * user's value and the calculated value as long as the user's - * value is larger than 0. The user's value is in pages. - */ - sges_per_frame = ((sc->reqframesz) / - sizeof(MPI2_SGE_SIMPLE64)) - 1; - cpi->maxio = (sges_per_frame * sc->facts->MaxChainDepth) + 1; - cpi->maxio *= PAGE_SIZE; - if ((sc->max_io_pages > 0) && (sc->max_io_pages * PAGE_SIZE < - cpi->maxio)) - cpi->maxio = sc->max_io_pages * PAGE_SIZE; + cpi->maxio = sc->maxio; mpssas_set_ccbstatus(ccb, CAM_REQ_CMP); break; } Index: head/sys/dev/mps/mpsvar.h =================================================================== --- head/sys/dev/mps/mpsvar.h +++ head/sys/dev/mps/mpsvar.h @@ -315,6 +315,7 @@ int chain_free; int max_chains; int max_io_pages; + u_int maxio; int chain_free_lowwater; u_int enable_ssu; int spinup_wait_time; @@ -349,6 +350,7 @@ int num_reqs; int num_prireqs; int num_replies; + int num_chains; int fqdepth; /* Free queue */ int pqdepth; /* Post queue */