Index: sys/mpt_ioctl.h =================================================================== RCS file: sys/mpt_ioctl.h diff -N sys/mpt_ioctl.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/mpt_ioctl.h 6 May 2008 18:23:33 -0000 @@ -0,0 +1,132 @@ +/*- + * Copyright (c) 2008 Yahoo!, Inc. + * All rights reserved. + * Written by: John Baldwin + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * LSI MPT-Fusion Host Adapter FreeBSD userland interface + * + * $FreeBSD$ + */ + +#ifndef _MPT_IOCTL_H_ +#define _MPT_IOCTL_H_ + +#include +#include +#include + +/* + * For the read header requests, the header should include the page + * type or extended page type, page number, and page version. The + * buffer and length are unused. The completed header is returned in + * the 'header' member. + * + * For the read page and write page requests, 'buf' should point to a + * buffer of 'len' bytes which holds the entire page (including the + * header). + * + * All requests specify the page address in 'page_address'. + */ +struct mpt_cfg_page_req { + CONFIG_PAGE_HEADER header; + uint32_t page_address; + void *buf; + int len; + uint16_t ioc_status; +}; + +struct mpt_ext_cfg_page_req { + CONFIG_EXTENDED_PAGE_HEADER header; + uint32_t page_address; + void *buf; + int len; + uint16_t ioc_status; +}; + +struct mpt_raid_action { + uint8_t action; + uint8_t volume_bus; + uint8_t volume_id; + uint8_t phys_disk_num; + uint32_t action_data_word; + void *buf; + int len; + uint32_t volume_status; + uint32_t action_data[4]; + uint16_t action_status; + uint16_t ioc_status; + uint8_t write; +}; + +#define MPTIO_READ_CFG_HEADER _IOWR('M', 100, struct mpt_cfg_page_req) +#define MPTIO_READ_CFG_PAGE _IOWR('M', 101, struct mpt_cfg_page_req) +#define MPTIO_READ_EXT_CFG_HEADER _IOWR('M', 102, struct mpt_ext_cfg_page_req) +#define MPTIO_READ_EXT_CFG_PAGE _IOWR('M', 103, struct mpt_ext_cfg_page_req) +#define MPTIO_WRITE_CFG_PAGE _IOWR('M', 104, struct mpt_cfg_page_req) +#define MPTIO_RAID_ACTION _IOWR('M', 105, struct mpt_raid_action) + +#if defined(__amd64__) +struct mpt_cfg_page_req32 { + CONFIG_PAGE_HEADER header; + uint32_t page_address; + uint32_t buf; + int len; + uint16_t ioc_status; +}; + +struct mpt_ext_cfg_page_req32 { + CONFIG_EXTENDED_PAGE_HEADER header; + uint32_t page_address; + uint32_t buf; + int len; + uint16_t ioc_status; +}; + +struct mpt_raid_action32 { + uint8_t action; + uint8_t volume_bus; + uint8_t volume_id; + uint8_t phys_disk_num; + uint32_t action_data_word; + uint32_t buf; + int len; + uint32_t volume_status; + uint32_t action_data[4]; + uint16_t action_status; + uint16_t ioc_status; + uint8_t write; +}; + +#define MPTIO_READ_CFG_HEADER32 _IOWR('M', 100, struct mpt_cfg_page_req32) +#define MPTIO_READ_CFG_PAGE32 _IOWR('M', 101, struct mpt_cfg_page_req32) +#define MPTIO_READ_EXT_CFG_HEADER32 _IOWR('M', 102, struct mpt_ext_cfg_page_req32) +#define MPTIO_READ_EXT_CFG_PAGE32 _IOWR('M', 103, struct mpt_ext_cfg_page_req32) +#define MPTIO_WRITE_CFG_PAGE32 _IOWR('M', 104, struct mpt_cfg_page_req32) +#define MPTIO_RAID_ACTION32 _IOWR('M', 105, struct mpt_raid_action32) +#endif + +#endif /* !_MPT_IOCTL_H_ */ Index: conf/files =================================================================== RCS file: /usr/cvs/src/sys/conf/files,v retrieving revision 1.1296 diff -u -r1.1296 files --- conf/files 29 Apr 2008 21:36:16 -0000 1.1296 +++ conf/files 6 May 2008 18:27:45 -0000 @@ -931,6 +931,7 @@ dev/mpt/mpt_debug.c optional mpt dev/mpt/mpt_pci.c optional mpt pci dev/mpt/mpt_raid.c optional mpt +dev/mpt/mpt_user.c optional mpt dev/msk/if_msk.c optional msk dev/mxge/if_mxge.c optional mxge pci dev/mxge/mxge_lro.c optional mxge pci Index: dev/mpt/mpt.h =================================================================== RCS file: /usr/cvs/src/sys/dev/mpt/mpt.h,v retrieving revision 1.45 diff -u -r1.45 mpt.h --- dev/mpt/mpt.h 2 May 2008 17:02:35 -0000 1.45 +++ dev/mpt/mpt.h 6 May 2008 18:28:06 -0000 @@ -785,6 +785,9 @@ /* Shutdown Event Handler. */ eventhandler_tag eh; + /* Userland management interface. */ + struct cdev *cdev; + TAILQ_ENTRY(mpt_softc) links; }; Index: dev/mpt/mpt_user.c =================================================================== RCS file: dev/mpt/mpt_user.c diff -N dev/mpt/mpt_user.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ dev/mpt/mpt_user.c 6 May 2008 18:27:14 -0000 @@ -0,0 +1,755 @@ +/*- + * Copyright (c) 2008 Yahoo!, Inc. + * All rights reserved. + * Written by: John Baldwin + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * LSI MPT-Fusion Host Adapter FreeBSD userland interface + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include + +struct mpt_user_raid_action_result { + uint32_t volume_status; + uint32_t action_data[4]; + uint16_t action_status; +}; + +static mpt_probe_handler_t mpt_user_probe; +static mpt_attach_handler_t mpt_user_attach; +static mpt_enable_handler_t mpt_user_enable; +static mpt_ready_handler_t mpt_user_ready; +static mpt_event_handler_t mpt_user_event; +static mpt_reset_handler_t mpt_user_reset; +static mpt_detach_handler_t mpt_user_detach; + +static struct mpt_personality mpt_user_personality = { + .name = "mpt_user", + .probe = mpt_user_probe, + .attach = mpt_user_attach, + .enable = mpt_user_enable, + .ready = mpt_user_ready, + .event = mpt_user_event, + .reset = mpt_user_reset, + .detach = mpt_user_detach, +}; + +DECLARE_MPT_PERSONALITY(mpt_user, SI_ORDER_SECOND); + +static mpt_reply_handler_t mpt_user_reply_handler; + +static d_open_t mpt_open; +static d_close_t mpt_close; +static d_ioctl_t mpt_ioctl; + +static struct cdevsw mpt_cdevsw = { + .d_version = D_VERSION, + .d_flags = 0, + .d_open = mpt_open, + .d_close = mpt_close, + .d_ioctl = mpt_ioctl, + .d_name = "mpt", +}; + +static MALLOC_DEFINE(M_MPTUSER, "mpt_user", "Buffers for mpt(4) ioctls"); + +static uint32_t user_handler_id = MPT_HANDLER_ID_NONE; + +int +mpt_user_probe(struct mpt_softc *mpt) +{ + + /* Attach to every controller. */ + return (0); +} + +int +mpt_user_attach(struct mpt_softc *mpt) +{ + mpt_handler_t handler; + int error, unit; + + MPT_LOCK(mpt); + handler.reply_handler = mpt_user_reply_handler; + error = mpt_register_handler(mpt, MPT_HANDLER_REPLY, handler, + &user_handler_id); + MPT_UNLOCK(mpt); + if (error != 0) { + mpt_prt(mpt, "Unable to register user handler!\n"); + return (error); + } + unit = device_get_unit(mpt->dev); + mpt->cdev = make_dev(&mpt_cdevsw, unit, UID_ROOT, GID_OPERATOR, 0640, + "mpt%d", unit); + if (mpt->cdev == NULL) { + MPT_LOCK(mpt); + mpt_deregister_handler(mpt, MPT_HANDLER_REPLY, handler, + user_handler_id); + MPT_UNLOCK(mpt); + return (ENOMEM); + } + mpt->cdev->si_drv1 = mpt; + return (0); +} + +int +mpt_user_enable(struct mpt_softc *mpt) +{ + + return (0); +} + +void +mpt_user_ready(struct mpt_softc *mpt) +{ +} + +int +mpt_user_event(struct mpt_softc *mpt, request_t *req, + MSG_EVENT_NOTIFY_REPLY *msg) +{ + + /* Someday we may want to let a user daemon listen for events? */ + return (0); +} + +void +mpt_user_reset(struct mpt_softc *mpt, int type) +{ +} + +void +mpt_user_detach(struct mpt_softc *mpt) +{ + mpt_handler_t handler; + + /* XXX: do a purge of pending requests? */ + destroy_dev(mpt->cdev); + + MPT_LOCK(mpt); + handler.reply_handler = mpt_user_reply_handler; + mpt_deregister_handler(mpt, MPT_HANDLER_REPLY, handler, + user_handler_id); + MPT_UNLOCK(mpt); +} + +static int +mpt_open(struct cdev *dev, int flags, int fmt, d_thread_t *td) +{ + + return (0); +} + +static int +mpt_close(struct cdev *dev, int flags, int fmt, d_thread_t *td) +{ + + return (0); +} + +static int +mpt_user_read_cfg_header(struct mpt_softc *mpt, + struct mpt_cfg_page_req *page_req) +{ + request_t *req; + cfgparms_t params; + MSG_CONFIG *cfgp; + int error; + + req = mpt_get_request(mpt, TRUE); + if (req == NULL) { + mpt_prt(mpt, "mpt_user_read_cfg_header: Get request failed!\n"); + return (ENOMEM); + } + + params.Action = MPI_CONFIG_ACTION_PAGE_HEADER; + params.PageVersion = 0; + params.PageLength = 0; + params.PageNumber = page_req->header.PageNumber; + params.PageType = page_req->header.PageType; + params.PageAddress = page_req->page_address; + error = mpt_issue_cfg_req(mpt, req, ¶ms, /*addr*/0, /*len*/0, + TRUE, 5000); + if (error != 0) { + /* + * Leave the request. Without resetting the chip, it's + * still owned by it and we'll just get into trouble + * freeing it now. Mark it as abandoned so that if it + * shows up later it can be freed. + */ + mpt_prt(mpt, "read_cfg_header timed out\n"); + return (ETIMEDOUT); + } + + page_req->ioc_status = req->IOCStatus; + if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS) { + cfgp = req->req_vbuf; + bcopy(&cfgp->Header, &page_req->header, + sizeof(page_req->header)); + } + mpt_free_request(mpt, req); + return (0); +} + +static int +mpt_user_read_cfg_page(struct mpt_softc *mpt, struct mpt_cfg_page_req *page_req, + void *mpt_page) +{ + CONFIG_PAGE_HEADER *hdr; + request_t *req; + cfgparms_t params; + int error; + + req = mpt_get_request(mpt, TRUE); + if (req == NULL) { + mpt_prt(mpt, "mpt_user_read_cfg_page: Get request failed!\n"); + return (ENOMEM); + } + + hdr = mpt_page; + 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, ¶ms, + req->req_pbuf + MPT_RQSL(mpt), + page_req->len, TRUE, 5000); + if (error != 0) { + mpt_prt(mpt, "mpt_user_read_cfg_page timed out\n"); + return (ETIMEDOUT); + } + + page_req->ioc_status = req->IOCStatus; + if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS) { + bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap, + BUS_DMASYNC_POSTREAD); + memcpy(mpt_page, ((uint8_t *)req->req_vbuf)+MPT_RQSL(mpt), + page_req->len); + } + mpt_free_request(mpt, req); + return (0); +} + +static int +mpt_user_read_extcfg_header(struct mpt_softc *mpt, + struct mpt_ext_cfg_page_req *ext_page_req) +{ + request_t *req; + cfgparms_t params; + MSG_CONFIG_REPLY *cfgp; + int error; + + req = mpt_get_request(mpt, TRUE); + if (req == NULL) { + mpt_prt(mpt, "mpt_user_read_extcfg_header: Get request failed!\n"); + return (ENOMEM); + } + + params.Action = MPI_CONFIG_ACTION_PAGE_HEADER; + params.PageVersion = ext_page_req->header.PageVersion; + params.PageLength = 0; + params.PageNumber = ext_page_req->header.PageNumber; + params.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; + params.PageAddress = ext_page_req->page_address; + params.ExtPageType = ext_page_req->header.ExtPageType; + params.ExtPageLength = 0; + error = mpt_issue_cfg_req(mpt, req, ¶ms, /*addr*/0, /*len*/0, + TRUE, 5000); + if (error != 0) { + /* + * Leave the request. Without resetting the chip, it's + * still owned by it and we'll just get into trouble + * freeing it now. Mark it as abandoned so that if it + * shows up later it can be freed. + */ + mpt_prt(mpt, "mpt_user_read_extcfg_header timed out\n"); + return (ETIMEDOUT); + } + + ext_page_req->ioc_status = req->IOCStatus; + if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS) { + cfgp = req->req_vbuf; + ext_page_req->header.PageVersion = cfgp->Header.PageVersion; + ext_page_req->header.PageNumber = cfgp->Header.PageNumber; + ext_page_req->header.PageType = cfgp->Header.PageType; + ext_page_req->header.ExtPageLength = cfgp->ExtPageLength; + ext_page_req->header.ExtPageType = cfgp->ExtPageType; + } + mpt_free_request(mpt, req); + return (0); +} + +static int +mpt_user_read_extcfg_page(struct mpt_softc *mpt, + struct mpt_ext_cfg_page_req *ext_page_req, void *mpt_page) +{ + CONFIG_EXTENDED_PAGE_HEADER *hdr; + request_t *req; + cfgparms_t params; + int error; + + req = mpt_get_request(mpt, TRUE); + if (req == NULL) { + mpt_prt(mpt, "mpt_user_read_extcfg_page: Get request failed!\n"); + return (ENOMEM); + } + + hdr = mpt_page; + params.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + params.PageVersion = hdr->PageVersion; + params.PageLength = 0; + params.PageNumber = hdr->PageNumber; + params.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; + params.PageAddress = ext_page_req->page_address; + params.ExtPageType = hdr->ExtPageType; + params.ExtPageLength = hdr->ExtPageLength; + error = mpt_issue_cfg_req(mpt, req, ¶ms, + req->req_pbuf + MPT_RQSL(mpt), + ext_page_req->len, TRUE, 5000); + if (error != 0) { + mpt_prt(mpt, "mpt_user_read_extcfg_page timed out\n"); + return (ETIMEDOUT); + } + + 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, + 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) +{ + CONFIG_PAGE_HEADER *hdr; + request_t *req; + cfgparms_t params; + u_int hdr_attr; + int error; + + hdr = mpt_page; + hdr_attr = hdr->PageType & MPI_CONFIG_PAGEATTR_MASK; + if (hdr_attr != MPI_CONFIG_PAGEATTR_CHANGEABLE && + hdr_attr != MPI_CONFIG_PAGEATTR_PERSISTENT) { + mpt_prt(mpt, "page type 0x%x not changeable\n", + hdr->PageType & MPI_CONFIG_PAGETYPE_MASK); + return (EINVAL); + } + +#if 0 + /* + * We shouldn't mask off other bits here. + */ + hdr->PageType &= ~MPI_CONFIG_PAGETYPE_MASK; +#endif + + req = mpt_get_request(mpt, TRUE); + if (req == NULL) + return (ENOMEM); + + memcpy(((caddr_t)req->req_vbuf) + MPT_RQSL(mpt), mpt_page, + page_req->len); + + /* + * There isn't any point in restoring stripped out attributes + * if you then mask them going down to issue the request. + */ + + params.Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; + params.PageVersion = hdr->PageVersion; + params.PageLength = hdr->PageLength; + params.PageNumber = hdr->PageNumber; + params.PageAddress = page_req->page_address; +#if 0 + /* Restore stripped out attributes */ + hdr->PageType |= hdr_attr; + params.PageType = hdr->PageType & MPI_CONFIG_PAGETYPE_MASK; +#else + params.PageType = hdr->PageType; +#endif + error = mpt_issue_cfg_req(mpt, req, ¶ms, + req->req_pbuf + MPT_RQSL(mpt), + page_req->len, TRUE, 5000); + if (error != 0) { + mpt_prt(mpt, "mpt_write_cfg_page timed out\n"); + return (ETIMEDOUT); + } + + page_req->ioc_status = req->IOCStatus; + mpt_free_request(mpt, req); + return (0); +} + +static int +mpt_user_reply_handler(struct mpt_softc *mpt, request_t *req, + uint32_t reply_desc, MSG_DEFAULT_REPLY *reply_frame) +{ + MSG_RAID_ACTION_REPLY *reply; + struct mpt_user_raid_action_result *res; + + if (req == NULL) + return (TRUE); + + if (reply_frame != NULL) { + bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap, + BUS_DMASYNC_POSTREAD); + reply = (MSG_RAID_ACTION_REPLY *)reply_frame; + req->IOCStatus = le16toh(reply->IOCStatus); + res = (struct mpt_user_raid_action_result *) + (((uint8_t *)req->req_vbuf) + MPT_RQSL(mpt)); + res->action_status = reply->ActionStatus; + res->volume_status = reply->VolumeStatus; + bcopy(&reply->ActionData, res->action_data, + sizeof(res->action_data)); + } + + req->state &= ~REQ_STATE_QUEUED; + req->state |= REQ_STATE_DONE; + TAILQ_REMOVE(&mpt->request_pending_list, req, links); + + if ((req->state & REQ_STATE_NEED_WAKEUP) != 0) { + wakeup(req); + } else if ((req->state & REQ_STATE_TIMEDOUT) != 0) { + /* + * Whew- we can free this request (late completion) + */ + mpt_free_request(mpt, req); + } + + return (TRUE); +} + +/* + * We use the first part of the request buffer after the request frame + * to hold the action data and action status from the RAID reply. The + * rest of the request buffer is used to hold the buffer for the + * action SGE. + */ +static int +mpt_user_raid_action(struct mpt_softc *mpt, struct mpt_raid_action *raid_act, + void *buf) +{ + request_t *req; + struct mpt_user_raid_action_result *res; + MSG_RAID_ACTION_REQUEST *rap; + SGE_SIMPLE32 *se; + int error; + + req = mpt_get_request(mpt, TRUE); + if (req == NULL) + return (ENOMEM); + rap = req->req_vbuf; + memset(rap, 0, sizeof *rap); + rap->Action = raid_act->action; + rap->ActionDataWord = raid_act->action_data_word; + rap->Function = MPI_FUNCTION_RAID_ACTION; + rap->VolumeID = raid_act->volume_id; + 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); + 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 | + MPI_SGE_FLAGS_END_OF_LIST | + raid_act->write ? MPI_SGE_FLAGS_HOST_TO_IOC : + MPI_SGE_FLAGS_IOC_TO_HOST)); + } + rap->MsgContext = htole32(req->index | user_handler_id); + + mpt_check_doorbell(mpt); + mpt_send_cmd(mpt, req); + + error = mpt_wait_req(mpt, req, REQ_STATE_DONE, REQ_STATE_DONE, TRUE, + 2000); + if (error != 0) { + /* + * Leave request so it can be cleaned up later. + */ + mpt_prt(mpt, "mpt_user_raid_action timed out\n"); + return (error); + } + + raid_act->ioc_status = req->IOCStatus; + if ((req->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { + mpt_free_request(mpt, req); + return (0); + } + + res = (struct mpt_user_raid_action_result *) + (((uint8_t *)req->req_vbuf) + MPT_RQSL(mpt)); + raid_act->volume_status = res->volume_status; + 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); + mpt_free_request(mpt, req); + return (0); +} + +#ifdef __amd64__ +#define PTRIN(p) ((void *)(uintptr_t)(p)) +#define PTROUT(v) ((u_int32_t)(uintptr_t)(v)) +#endif + +static int +mpt_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td) +{ + struct mpt_softc *mpt; + struct mpt_cfg_page_req *page_req; + struct mpt_ext_cfg_page_req *ext_page_req; + struct mpt_raid_action *raid_act; +#ifdef __amd64__ + struct mpt_cfg_page_req32 *page_req32; + struct mpt_cfg_page_req page_req_swab; + struct mpt_ext_cfg_page_req32 *ext_page_req32; + struct mpt_ext_cfg_page_req ext_page_req_swab; + 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; + +#ifdef __amd64__ + /* Convert 32-bit structs to native ones. */ + page_req32 = (void *)arg; + ext_page_req32 = (void *)arg; + raid_act32 = (void *)arg; + switch (cmd) { + case MPTIO_READ_CFG_HEADER32: + case MPTIO_READ_CFG_PAGE32: + case MPTIO_WRITE_CFG_PAGE32: + page_req = &page_req_swab; + page_req->header = page_req32->header; + page_req->page_address = page_req32->page_address; + page_req->buf = PTRIN(page_req32->buf); + page_req->len = page_req32->len; + page_req->ioc_status = page_req32->ioc_status; + break; + case MPTIO_READ_EXT_CFG_HEADER32: + case MPTIO_READ_EXT_CFG_PAGE32: + ext_page_req = &ext_page_req_swab; + ext_page_req->header = ext_page_req32->header; + ext_page_req->page_address = ext_page_req32->page_address; + ext_page_req->buf = PTRIN(ext_page_req32->buf); + ext_page_req->len = ext_page_req32->len; + ext_page_req->ioc_status = ext_page_req32->ioc_status; + break; + case MPTIO_RAID_ACTION32: + raid_act = &raid_act_swab; + raid_act->action = raid_act32->action; + raid_act->volume_bus = raid_act32->volume_bus; + raid_act->volume_id = raid_act32->volume_id; + raid_act->phys_disk_num = raid_act32->phys_disk_num; + raid_act->action_data_word = raid_act32->action_data_word; + raid_act->buf = PTRIN(raid_act32->buf); + raid_act->len = raid_act32->len; + raid_act->volume_status = raid_act32->volume_status; + bcopy(raid_act32->action_data, raid_act->action_data, + sizeof(raid_act->action_data)); + raid_act->action_status = raid_act32->action_status; + raid_act->ioc_status = raid_act32->ioc_status; + raid_act->write = raid_act32->write; + break; + } +#endif + + switch (cmd) { +#ifdef __amd64__ + case MPTIO_READ_CFG_HEADER32: +#endif + case MPTIO_READ_CFG_HEADER: + MPT_LOCK(mpt); + error = mpt_user_read_cfg_header(mpt, page_req); + MPT_UNLOCK(mpt); + break; +#ifdef __amd64__ + case MPTIO_READ_CFG_PAGE32: +#endif + case MPTIO_READ_CFG_PAGE: + if (page_req->len > (MPT_REQUEST_AREA - MPT_RQSL(mpt))) { + error = EINVAL; + break; + } + mpt_page = malloc(page_req->len, M_MPTUSER, M_WAITOK); + error = copyin(page_req->buf, mpt_page, + sizeof(CONFIG_PAGE_HEADER)); + if (error) + break; + MPT_LOCK(mpt); + 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); + break; +#ifdef __amd64__ + case MPTIO_READ_EXT_CFG_HEADER32: +#endif + case MPTIO_READ_EXT_CFG_HEADER: + MPT_LOCK(mpt); + error = mpt_user_read_extcfg_header(mpt, ext_page_req); + MPT_UNLOCK(mpt); + break; +#ifdef __amd64__ + 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; + break; + } + mpt_page = malloc(ext_page_req->len, M_MPTUSER, M_WAITOK); + error = copyin(ext_page_req->buf, mpt_page, + sizeof(CONFIG_EXTENDED_PAGE_HEADER)); + if (error) + break; + MPT_LOCK(mpt); + 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); + 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; + break; + } + mpt_page = malloc(page_req->len, M_MPTUSER, M_WAITOK); + error = copyin(page_req->buf, mpt_page, page_req->len); + if (error) + break; + MPT_LOCK(mpt); + error = mpt_user_write_cfg_page(mpt, page_req, mpt_page); + MPT_UNLOCK(mpt); + break; +#ifdef __amd64__ + case MPTIO_RAID_ACTION32: +#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; + break; + } + mpt_page = malloc(raid_act->len, M_MPTUSER, M_WAITOK); + error = copyin(raid_act->buf, mpt_page, raid_act->len); + if (error) + break; + } + MPT_LOCK(mpt); + 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); + break; + default: + error = ENOIOCTL; + break; + } + + if (mpt_page != NULL) + free(mpt_page, M_MPTUSER); + + if (error) + return (error); + +#ifdef __amd64__ + /* Convert native structs to 32-bit ones. */ + switch (cmd) { + case MPTIO_READ_CFG_HEADER32: + case MPTIO_READ_CFG_PAGE32: + case MPTIO_WRITE_CFG_PAGE32: + page_req32->header = page_req->header; + page_req32->page_address = page_req->page_address; + page_req32->buf = PTROUT(page_req->buf); + page_req32->len = page_req->len; + page_req32->ioc_status = page_req->ioc_status; + break; + case MPTIO_READ_EXT_CFG_HEADER32: + case MPTIO_READ_EXT_CFG_PAGE32: + ext_page_req32->header = ext_page_req->header; + ext_page_req32->page_address = ext_page_req->page_address; + ext_page_req32->buf = PTROUT(ext_page_req->buf); + ext_page_req32->len = ext_page_req->len; + ext_page_req32->ioc_status = ext_page_req->ioc_status; + break; + case MPTIO_RAID_ACTION32: + raid_act32->action = raid_act->action; + raid_act32->volume_bus = raid_act->volume_bus; + raid_act32->volume_id = raid_act->volume_id; + raid_act32->phys_disk_num = raid_act->phys_disk_num; + raid_act32->action_data_word = raid_act->action_data_word; + raid_act32->buf = PTROUT(raid_act->buf); + raid_act32->len = raid_act->len; + raid_act32->volume_status = raid_act->volume_status; + bcopy(raid_act->action_data, raid_act32->action_data, + sizeof(raid_act->action_data)); + raid_act32->action_status = raid_act->action_status; + raid_act32->ioc_status = raid_act->ioc_status; + raid_act32->write = raid_act->write; + break; + } +#endif + + return (0); +} Index: modules/mpt/Makefile =================================================================== RCS file: /usr/cvs/src/sys/modules/mpt/Makefile,v retrieving revision 1.2 diff -u -r1.2 Makefile --- modules/mpt/Makefile 10 Jul 2005 15:07:57 -0000 1.2 +++ modules/mpt/Makefile 6 May 2008 18:25:10 -0000 @@ -5,6 +5,6 @@ KMOD= mpt SRCS= bus_if.h device_if.h pci_if.h \ opt_cam.h opt_ddb.h \ - mpt.c mpt_cam.c mpt_debug.c mpt_pci.c mpt_raid.c + mpt.c mpt_cam.c mpt_debug.c mpt_pci.c mpt_raid.c mpt_user.c .include