1
0
mirror of https://git.FreeBSD.org/src.git synced 2025-01-30 16:51:41 +00:00

Rework how the mpt_user personality handles buffers for config pages.

Previously we reused the space in the request buffer after the request
header to hold config pages during a transaction.  This does not work when
reading large pages however.  Also, we were already malloc'ing a buffer to
do a copyin/copyout w/o holding locks that was then copied into/out of the
request buffer.  Instead, go ahead and use bus dma to alloc a buffer for
each config page request (and RAID actions that have an associated
ActionSGE).  This results in fewer data copies and allows for larger sized
requests.  For now the maximum size of a request is arbitrarily limited to
16 MB.

MFC after:	2 weeks
This commit is contained in:
John Baldwin 2008-07-01 19:48:15 +00:00
parent 0328507287
commit 4124f62e4f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=180153

View File

@ -47,6 +47,13 @@ struct mpt_user_raid_action_result {
uint16_t action_status;
};
struct mpt_page_memory {
bus_dma_tag_t tag;
bus_dmamap_t map;
bus_addr_t paddr;
void *vaddr;
};
static mpt_probe_handler_t mpt_user_probe;
static mpt_attach_handler_t mpt_user_attach;
static mpt_enable_handler_t mpt_user_enable;
@ -179,6 +186,56 @@ mpt_close(struct cdev *dev, int flags, int fmt, d_thread_t *td)
return (0);
}
static int
mpt_alloc_buffer(struct mpt_softc *mpt, struct mpt_page_memory *page_mem,
size_t len)
{
struct mpt_map_info mi;
int error;
page_mem->vaddr = NULL;
/* Limit requests to 16M. */
if (len > 16 * 1024 * 1024)
return (ENOSPC);
error = mpt_dma_tag_create(mpt, mpt->parent_dmat, 1, 0,
BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
len, 1, len, 0, &page_mem->tag);
if (error)
return (error);
error = bus_dmamem_alloc(page_mem->tag, &page_mem->vaddr,
BUS_DMA_NOWAIT, &page_mem->map);
if (error) {
bus_dma_tag_destroy(page_mem->tag);
return (error);
}
mi.mpt = mpt;
error = bus_dmamap_load(page_mem->tag, page_mem->map, page_mem->vaddr,
len, mpt_map_rquest, &mi, BUS_DMA_NOWAIT);
if (error == 0)
error = mi.error;
if (error) {
bus_dmamem_free(page_mem->tag, page_mem->vaddr, page_mem->map);
bus_dma_tag_destroy(page_mem->tag);
page_mem->vaddr = NULL;
return (error);
}
page_mem->paddr = mi.phys;
return (0);
}
static void
mpt_free_buffer(struct mpt_page_memory *page_mem)
{
if (page_mem->vaddr == NULL)
return;
bus_dmamap_unload(page_mem->tag, page_mem->map);
bus_dmamem_free(page_mem->tag, page_mem->vaddr, page_mem->map);
bus_dma_tag_destroy(page_mem->tag);
page_mem->vaddr = NULL;
}
static int
mpt_user_read_cfg_header(struct mpt_softc *mpt,
struct mpt_cfg_page_req *page_req)
@ -225,7 +282,7 @@ mpt_user_read_cfg_header(struct mpt_softc *mpt,
static int
mpt_user_read_cfg_page(struct mpt_softc *mpt, struct mpt_cfg_page_req *page_req,
void *mpt_page)
struct mpt_page_memory *mpt_page)
{
CONFIG_PAGE_HEADER *hdr;
request_t *req;
@ -238,15 +295,14 @@ mpt_user_read_cfg_page(struct mpt_softc *mpt, struct mpt_cfg_page_req *page_req,
return (ENOMEM);
}
hdr = mpt_page;
hdr = mpt_page->vaddr;
params.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
params.PageVersion = hdr->PageVersion;
params.PageLength = hdr->PageLength;
params.PageNumber = hdr->PageNumber;
params.PageType = hdr->PageType & MPI_CONFIG_PAGETYPE_MASK;
params.PageAddress = page_req->page_address;
error = mpt_issue_cfg_req(mpt, req, &params,
req->req_pbuf + MPT_RQSL(mpt),
error = mpt_issue_cfg_req(mpt, req, &params, mpt_page->paddr,
page_req->len, TRUE, 5000);
if (error != 0) {
mpt_prt(mpt, "mpt_user_read_cfg_page timed out\n");
@ -254,12 +310,9 @@ mpt_user_read_cfg_page(struct mpt_softc *mpt, struct mpt_cfg_page_req *page_req,
}
page_req->ioc_status = req->IOCStatus;
if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS) {
bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap,
if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS)
bus_dmamap_sync(mpt_page->tag, mpt_page->map,
BUS_DMASYNC_POSTREAD);
memcpy(mpt_page, ((uint8_t *)req->req_vbuf)+MPT_RQSL(mpt),
page_req->len);
}
mpt_free_request(mpt, req);
return (0);
}
@ -315,7 +368,7 @@ mpt_user_read_extcfg_header(struct mpt_softc *mpt,
static int
mpt_user_read_extcfg_page(struct mpt_softc *mpt,
struct mpt_ext_cfg_page_req *ext_page_req, void *mpt_page)
struct mpt_ext_cfg_page_req *ext_page_req, struct mpt_page_memory *mpt_page)
{
CONFIG_EXTENDED_PAGE_HEADER *hdr;
request_t *req;
@ -328,7 +381,7 @@ mpt_user_read_extcfg_page(struct mpt_softc *mpt,
return (ENOMEM);
}
hdr = mpt_page;
hdr = mpt_page->vaddr;
params.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
params.PageVersion = hdr->PageVersion;
params.PageLength = 0;
@ -337,8 +390,7 @@ mpt_user_read_extcfg_page(struct mpt_softc *mpt,
params.PageAddress = ext_page_req->page_address;
params.ExtPageType = hdr->ExtPageType;
params.ExtPageLength = hdr->ExtPageLength;
error = mpt_issue_cfg_req(mpt, req, &params,
req->req_pbuf + MPT_RQSL(mpt),
error = mpt_issue_cfg_req(mpt, req, &params, mpt_page->paddr,
ext_page_req->len, TRUE, 5000);
if (error != 0) {
mpt_prt(mpt, "mpt_user_read_extcfg_page timed out\n");
@ -346,19 +398,16 @@ mpt_user_read_extcfg_page(struct mpt_softc *mpt,
}
ext_page_req->ioc_status = req->IOCStatus;
if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS) {
bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap,
if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS)
bus_dmamap_sync(mpt_page->tag, mpt_page->map,
BUS_DMASYNC_POSTREAD);
memcpy(mpt_page, ((uint8_t *)req->req_vbuf)+MPT_RQSL(mpt),
ext_page_req->len);
}
mpt_free_request(mpt, req);
return (0);
}
static int
mpt_user_write_cfg_page(struct mpt_softc *mpt,
struct mpt_cfg_page_req *page_req, void *mpt_page)
struct mpt_cfg_page_req *page_req, struct mpt_page_memory *mpt_page)
{
CONFIG_PAGE_HEADER *hdr;
request_t *req;
@ -366,7 +415,7 @@ mpt_user_write_cfg_page(struct mpt_softc *mpt,
u_int hdr_attr;
int error;
hdr = mpt_page;
hdr = mpt_page->vaddr;
hdr_attr = hdr->PageType & MPI_CONFIG_PAGEATTR_MASK;
if (hdr_attr != MPI_CONFIG_PAGEATTR_CHANGEABLE &&
hdr_attr != MPI_CONFIG_PAGEATTR_PERSISTENT) {
@ -386,8 +435,7 @@ mpt_user_write_cfg_page(struct mpt_softc *mpt,
if (req == NULL)
return (ENOMEM);
memcpy(((caddr_t)req->req_vbuf) + MPT_RQSL(mpt), mpt_page,
page_req->len);
bus_dmamap_sync(mpt_page->tag, mpt_page->map, BUS_DMASYNC_PREWRITE);
/*
* There isn't any point in restoring stripped out attributes
@ -406,8 +454,7 @@ mpt_user_write_cfg_page(struct mpt_softc *mpt,
#else
params.PageType = hdr->PageType;
#endif
error = mpt_issue_cfg_req(mpt, req, &params,
req->req_pbuf + MPT_RQSL(mpt),
error = mpt_issue_cfg_req(mpt, req, &params, mpt_page->paddr,
page_req->len, TRUE, 5000);
if (error != 0) {
mpt_prt(mpt, "mpt_write_cfg_page timed out\n");
@ -466,7 +513,7 @@ mpt_user_reply_handler(struct mpt_softc *mpt, request_t *req,
*/
static int
mpt_user_raid_action(struct mpt_softc *mpt, struct mpt_raid_action *raid_act,
void *buf)
struct mpt_page_memory *mpt_page)
{
request_t *req;
struct mpt_user_raid_action_result *res;
@ -486,12 +533,10 @@ mpt_user_raid_action(struct mpt_softc *mpt, struct mpt_raid_action *raid_act,
rap->VolumeBus = raid_act->volume_bus;
rap->PhysDiskNum = raid_act->phys_disk_num;
se = (SGE_SIMPLE32 *)&rap->ActionDataSGE;
if (buf != 0 && raid_act->len != 0) {
memcpy(((caddr_t)req->req_vbuf) + MPT_RQSL(mpt) +
sizeof(struct mpt_user_raid_action_result), buf,
raid_act->len);
se->Address = req->req_pbuf + MPT_RQSL(mpt) +
sizeof(struct mpt_user_raid_action_result);
if (mpt_page->vaddr != NULL && raid_act->len != 0) {
bus_dmamap_sync(mpt_page->tag, mpt_page->map,
BUS_DMASYNC_PREWRITE);
se->Address = mpt_page->paddr;
MPI_pSGE_SET_LENGTH(se, raid_act->len);
MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
@ -526,9 +571,9 @@ mpt_user_raid_action(struct mpt_softc *mpt, struct mpt_raid_action *raid_act,
raid_act->action_status = res->action_status;
bcopy(res->action_data, raid_act->action_data,
sizeof(res->action_data));
if (buf != NULL)
memcpy(buf, ((uint8_t *)req->req_vbuf) + MPT_RQSL(mpt) +
sizeof(struct mpt_user_raid_action_result), raid_act->len);
if (mpt_page->vaddr != NULL)
bus_dmamap_sync(mpt_page->tag, mpt_page->map,
BUS_DMASYNC_POSTREAD);
mpt_free_request(mpt, req);
return (0);
}
@ -545,6 +590,7 @@ mpt_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
struct mpt_cfg_page_req *page_req;
struct mpt_ext_cfg_page_req *ext_page_req;
struct mpt_raid_action *raid_act;
struct mpt_page_memory mpt_page;
#ifdef __amd64__
struct mpt_cfg_page_req32 *page_req32;
struct mpt_cfg_page_req page_req_swab;
@ -553,14 +599,13 @@ mpt_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
struct mpt_raid_action32 *raid_act32;
struct mpt_raid_action raid_act_swab;
#endif
void *mpt_page;
int error;
mpt = dev->si_drv1;
page_req = (void *)arg;
ext_page_req = (void *)arg;
raid_act = (void *)arg;
mpt_page = NULL;
mpt_page.vaddr = NULL;
#ifdef __amd64__
/* Convert 32-bit structs to native ones. */
@ -619,21 +664,19 @@ mpt_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
case MPTIO_READ_CFG_PAGE32:
#endif
case MPTIO_READ_CFG_PAGE:
if (page_req->len > (MPT_REQUEST_AREA - MPT_RQSL(mpt))) {
error = EINVAL;
error = mpt_alloc_buffer(mpt, &mpt_page, page_req->len);
if (error)
break;
}
mpt_page = malloc(page_req->len, M_MPTUSER, M_WAITOK);
error = copyin(page_req->buf, mpt_page,
error = copyin(page_req->buf, mpt_page.vaddr,
sizeof(CONFIG_PAGE_HEADER));
if (error)
break;
MPT_LOCK(mpt);
error = mpt_user_read_cfg_page(mpt, page_req, mpt_page);
error = mpt_user_read_cfg_page(mpt, page_req, &mpt_page);
MPT_UNLOCK(mpt);
if (error)
break;
error = copyout(mpt_page, page_req->buf, page_req->len);
error = copyout(mpt_page.vaddr, page_req->buf, page_req->len);
break;
#ifdef __amd64__
case MPTIO_READ_EXT_CFG_HEADER32:
@ -647,36 +690,33 @@ mpt_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
case MPTIO_READ_EXT_CFG_PAGE32:
#endif
case MPTIO_READ_EXT_CFG_PAGE:
if (ext_page_req->len > (MPT_REQUEST_AREA - MPT_RQSL(mpt))) {
error = EINVAL;
error = mpt_alloc_buffer(mpt, &mpt_page, ext_page_req->len);
if (error)
break;
}
mpt_page = malloc(ext_page_req->len, M_MPTUSER, M_WAITOK);
error = copyin(ext_page_req->buf, mpt_page,
error = copyin(ext_page_req->buf, mpt_page.vaddr,
sizeof(CONFIG_EXTENDED_PAGE_HEADER));
if (error)
break;
MPT_LOCK(mpt);
error = mpt_user_read_extcfg_page(mpt, ext_page_req, mpt_page);
error = mpt_user_read_extcfg_page(mpt, ext_page_req, &mpt_page);
MPT_UNLOCK(mpt);
if (error)
break;
error = copyout(mpt_page, ext_page_req->buf, ext_page_req->len);
error = copyout(mpt_page.vaddr, ext_page_req->buf,
ext_page_req->len);
break;
#ifdef __amd64__
case MPTIO_WRITE_CFG_PAGE32:
#endif
case MPTIO_WRITE_CFG_PAGE:
if (page_req->len > (MPT_REQUEST_AREA - MPT_RQSL(mpt))) {
error = EINVAL;
error = mpt_alloc_buffer(mpt, &mpt_page, page_req->len);
if (error)
break;
}
mpt_page = malloc(page_req->len, M_MPTUSER, M_WAITOK);
error = copyin(page_req->buf, mpt_page, page_req->len);
error = copyin(page_req->buf, mpt_page.vaddr, page_req->len);
if (error)
break;
MPT_LOCK(mpt);
error = mpt_user_write_cfg_page(mpt, page_req, mpt_page);
error = mpt_user_write_cfg_page(mpt, page_req, &mpt_page);
MPT_UNLOCK(mpt);
break;
#ifdef __amd64__
@ -684,31 +724,29 @@ mpt_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
#endif
case MPTIO_RAID_ACTION:
if (raid_act->buf != NULL) {
if (raid_act->len >
(MPT_REQUEST_AREA - MPT_RQSL(mpt) -
sizeof(struct mpt_user_raid_action_result))) {
error = EINVAL;
error = mpt_alloc_buffer(mpt, &mpt_page, raid_act->len);
if (error)
break;
}
mpt_page = malloc(raid_act->len, M_MPTUSER, M_WAITOK);
error = copyin(raid_act->buf, mpt_page, raid_act->len);
error = copyin(raid_act->buf, mpt_page.vaddr,
raid_act->len);
if (error)
break;
}
MPT_LOCK(mpt);
error = mpt_user_raid_action(mpt, raid_act, mpt_page);
error = mpt_user_raid_action(mpt, raid_act, &mpt_page);
MPT_UNLOCK(mpt);
if (error)
break;
error = copyout(mpt_page, raid_act->buf, raid_act->len);
if (raid_act->buf != NULL)
error = copyout(mpt_page.vaddr, raid_act->buf,
raid_act->len);
break;
default:
error = ENOIOCTL;
break;
}
if (mpt_page != NULL)
free(mpt_page, M_MPTUSER);
mpt_free_buffer(&mpt_page);
if (error)
return (error);