Index: mrsas.c =================================================================== --- mrsas.c (revision 295762) +++ mrsas.c (working copy) @@ -163,6 +163,7 @@ extern int mrsas_bus_scan_sim(struct mrsas_softc *sc, struct cam_sim *sim); static int mrsas_alloc_evt_log_info_cmd(struct mrsas_softc *sc); static void mrsas_free_evt_log_info_cmd(struct mrsas_softc *sc); +static void mrsas_handle_evt(void *context, int pending); SYSCTL_NODE(_hw, OID_AUTO, mrsas, CTLFLAG_RD, 0, "MRSAS Driver Parameters"); @@ -408,6 +409,10 @@ OID_AUTO, "disable_ocr", CTLFLAG_RW, &sc->disableOnlineCtrlReset, 0, "Disable the use of OCR"); + SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "fast_path", CTLFLAG_RW, &sc->fast_path_io, 0, + "fast path"); + SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO, "driver_version", CTLFLAG_RD, MRSAS_VERSION, strlen(MRSAS_VERSION), "driver version"); @@ -493,8 +498,8 @@ el_info_size = sizeof(struct mrsas_evt_log_info); if (bus_dma_tag_create(sc->mrsas_parent_tag, 1, 0, - BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, + BUS_SPACE_MAXADDR, NULL, NULL, el_info_size, 1, @@ -573,12 +578,19 @@ dcmd->cmd_status = 0x0; dcmd->sge_count = 1; dcmd->flags = MFI_FRAME_DIR_READ; + if (sizeof(bus_addr_t) == 8) + dcmd->flags |= MFI_FRAME_SGL64; dcmd->timeout = 0; dcmd->pad_0 = 0; dcmd->data_xfer_len = sizeof(struct mrsas_evt_log_info); dcmd->opcode = MR_DCMD_CTRL_EVENT_GET_INFO; - dcmd->sgl.sge32[0].phys_addr = sc->el_info_phys_addr; - dcmd->sgl.sge32[0].length = sizeof(struct mrsas_evt_log_info); + if ((dcmd->flags & MFI_FRAME_SGL64) == MFI_FRAME_SGL64) { + dcmd->sgl.sge64[0].phys_addr = sc->el_info_phys_addr; + dcmd->sgl.sge64[0].length = sizeof(struct mrsas_evt_log_info); + } else { + dcmd->sgl.sge32[0].phys_addr = sc->el_info_phys_addr; + dcmd->sgl.sge32[0].length = sizeof(struct mrsas_evt_log_info); + } mrsas_issue_blocked_cmd(sc, cmd); @@ -681,6 +693,8 @@ dcmd->cmd_status = 0x0; dcmd->sge_count = 1; dcmd->flags = MFI_FRAME_DIR_READ; + if (sizeof(bus_addr_t) == 8) + dcmd->flags |= MFI_FRAME_SGL64; dcmd->timeout = 0; dcmd->pad_0 = 0; dcmd->data_xfer_len = sizeof(struct mrsas_evt_detail); @@ -688,8 +702,15 @@ dcmd->mbox.w[0] = seq_num; sc->last_seq_num = seq_num; dcmd->mbox.w[1] = curr_aen.word; - dcmd->sgl.sge32[0].phys_addr = (u_int32_t)sc->evt_detail_phys_addr; - dcmd->sgl.sge32[0].length = sizeof(struct mrsas_evt_detail); + if ((dcmd->flags & MFI_FRAME_SGL64) == MFI_FRAME_SGL64) { + dcmd->sgl.sge64[0].phys_addr = + (u_int32_t)sc->evt_detail_phys_addr; + dcmd->sgl.sge64[0].length = sizeof(struct mrsas_evt_detail); + } else { + dcmd->sgl.sge32[0].phys_addr = + (u_int32_t)sc->evt_detail_phys_addr; + dcmd->sgl.sge32[0].length = sizeof(struct mrsas_evt_detail); + } if (sc->aen_cmd != NULL) { mrsas_release_mfi_cmd(cmd); @@ -881,6 +902,9 @@ sc->msix_enable = 0; + TAILQ_INIT(&sc->mrsas_evt_queue); + TASK_INIT(&sc->mrsas_evt_task, 0, mrsas_handle_evt, sc); + /* Initialize Firmware */ if (mrsas_init_fw(sc) != SUCCESS) { goto attach_fail_fw; @@ -1301,7 +1325,14 @@ int ret = 0, i = 0; MRSAS_DRV_PCI_INFORMATION *pciDrvInfo; - sc = mrsas_get_softc_instance(dev, cmd, arg); + switch (cmd) { + case MFIIO_PASSTHRU: + sc = (struct mrsas_softc *)(dev->si_drv1); + break; + default: + sc = mrsas_get_softc_instance(dev, cmd, arg); + break; + } if (!sc) return ENOENT; @@ -1329,7 +1360,7 @@ do_ioctl: switch (cmd) { - case MRSAS_IOC_FIRMWARE_PASS_THROUGH64: + case MRSAS_IOC_FIRMWARE_PASS_THROUGH: #ifdef COMPAT_FREEBSD32 case MRSAS_IOC_FIRMWARE_PASS_THROUGH32: #endif @@ -1364,6 +1395,10 @@ ret = 0; break; + case MFIIO_PASSTHRU: + ret = mrsas_user_command(sc, (struct mfi_ioc_passthru *)arg); + break; + default: mrsas_dprint(sc, MRSAS_TRACE, "IOCTL command 0x%lx is not handled\n", cmd); ret = ENOENT; @@ -1683,15 +1718,16 @@ /* * Allocate parent DMA tag */ - if (bus_dma_tag_create(NULL, /* parent */ + if (bus_dma_tag_create( + bus_get_dma_tag(sc->mrsas_dev), /* parent */ 1, /* alignment */ 0, /* boundary */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ - MRSAS_MAX_IO_SIZE, /* maxsize */ - MRSAS_MAX_SGL, /* nsegments */ - MRSAS_MAX_IO_SIZE, /* maxsegsize */ + BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ + BUS_SPACE_UNRESTRICTED, /* nsegments */ + BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 0, /* flags */ NULL, NULL, /* lockfunc, lockarg */ &sc->mrsas_parent_tag /* tag */ @@ -1700,7 +1736,7 @@ return (ENOMEM); } /* - * Allocate for version buffer + * Allocate for version buffer 32bit _lo */ verbuf_size = MRSAS_MAX_NAME_LENGTH * (sizeof(bus_addr_t)); if (bus_dma_tag_create(sc->mrsas_parent_tag, @@ -1735,8 +1771,8 @@ io_req_size = sc->io_frames_alloc_sz; if (bus_dma_tag_create(sc->mrsas_parent_tag, 16, 0, - BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, + BUS_SPACE_MAXADDR, NULL, NULL, io_req_size, 1, @@ -1765,8 +1801,8 @@ chain_frame_size = sc->chain_frames_alloc_sz; if (bus_dma_tag_create(sc->mrsas_parent_tag, 4, 0, - BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, + BUS_SPACE_MAXADDR, NULL, NULL, chain_frame_size, 1, @@ -1796,8 +1832,8 @@ reply_desc_size = sc->reply_alloc_sz * count; if (bus_dma_tag_create(sc->mrsas_parent_tag, 16, 0, - BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, + BUS_SPACE_MAXADDR, NULL, NULL, reply_desc_size, 1, @@ -1854,8 +1890,8 @@ evt_detail_size = sizeof(struct mrsas_evt_detail); if (bus_dma_tag_create(sc->mrsas_parent_tag, 1, 0, - BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, + BUS_SPACE_MAXADDR, NULL, NULL, evt_detail_size, 1, @@ -1947,8 +1983,8 @@ for (int i = 0; i < 2; i++) { if (bus_dma_tag_create(sc->mrsas_parent_tag, 4, 0, - BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, + BUS_SPACE_MAXADDR, NULL, NULL, sc->max_map_sz, 1, @@ -2219,8 +2255,8 @@ ioc_init_size = 1024 + sizeof(MPI2_IOC_INIT_REQUEST); if (bus_dma_tag_create(sc->mrsas_parent_tag, 1, 0, - BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, + BUS_SPACE_MAXADDR, NULL, NULL, ioc_init_size, 1, @@ -3041,12 +3077,19 @@ dcmd->cmd_status = 0xFF; dcmd->sge_count = 1; dcmd->flags = MFI_FRAME_DIR_READ; + if (sizeof(bus_addr_t) == 8) + dcmd->flags |= MFI_FRAME_SGL64; dcmd->timeout = 0; dcmd->pad_0 = 0; dcmd->data_xfer_len = sizeof(struct mrsas_ctrl_info); dcmd->opcode = MR_DCMD_CTRL_GET_INFO; - dcmd->sgl.sge32[0].phys_addr = sc->ctlr_info_phys_addr; - dcmd->sgl.sge32[0].length = sizeof(struct mrsas_ctrl_info); + if ((dcmd->flags & MFI_FRAME_SGL64) == MFI_FRAME_SGL64) { + dcmd->sgl.sge64[0].phys_addr = sc->ctlr_info_phys_addr; + dcmd->sgl.sge64[0].length = sizeof(struct mrsas_ctrl_info); + } else { + dcmd->sgl.sge32[0].phys_addr = sc->ctlr_info_phys_addr; + dcmd->sgl.sge32[0].length = sizeof(struct mrsas_ctrl_info); + } if (!mrsas_issue_polled(sc, cmd)) memcpy(sc->ctrl_info, sc->ctlr_info_mem, sizeof(struct mrsas_ctrl_info)); @@ -3117,8 +3160,8 @@ ctlr_info_size = sizeof(struct mrsas_ctrl_info); if (bus_dma_tag_create(sc->mrsas_parent_tag, 1, 0, - BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, + BUS_SPACE_MAXADDR, NULL, NULL, ctlr_info_size, 1, @@ -3618,12 +3661,19 @@ dcmd->cmd_status = 0xFF; dcmd->sge_count = 1; dcmd->flags = MFI_FRAME_DIR_READ; + if (sizeof(bus_addr_t) == 8) + dcmd->flags |= MFI_FRAME_SGL64; dcmd->timeout = 0; dcmd->pad_0 = 0; dcmd->data_xfer_len = sc->current_map_sz; dcmd->opcode = MR_DCMD_LD_MAP_GET_INFO; - dcmd->sgl.sge32[0].phys_addr = map_phys_addr; - dcmd->sgl.sge32[0].length = sc->current_map_sz; + if ((dcmd->flags & MFI_FRAME_SGL64) == MFI_FRAME_SGL64) { + dcmd->sgl.sge64[0].phys_addr = map_phys_addr; + dcmd->sgl.sge64[0].length = sc->current_map_sz; + } else { + dcmd->sgl.sge32[0].phys_addr = map_phys_addr; + dcmd->sgl.sge32[0].length = sc->current_map_sz; + } if (!mrsas_issue_polled(sc, cmd)) retcode = 0; @@ -3687,6 +3737,8 @@ dcmd->cmd_status = 0xFF; dcmd->sge_count = 1; dcmd->flags = MFI_FRAME_DIR_WRITE; + if (sizeof(bus_addr_t) == 8) + dcmd->flags |= MFI_FRAME_SGL64; dcmd->timeout = 0; dcmd->pad_0 = 0; dcmd->data_xfer_len = sc->current_map_sz; @@ -3693,8 +3745,13 @@ dcmd->mbox.b[0] = num_lds; dcmd->mbox.b[1] = MRSAS_DCMD_MBOX_PEND_FLAG; dcmd->opcode = MR_DCMD_LD_MAP_GET_INFO; - dcmd->sgl.sge32[0].phys_addr = map_phys_addr; - dcmd->sgl.sge32[0].length = sc->current_map_sz; + if ((dcmd->flags & MFI_FRAME_SGL64) == MFI_FRAME_SGL64) { + dcmd->sgl.sge64[0].phys_addr = map_phys_addr; + dcmd->sgl.sge64[0].length = sc->current_map_sz; + } else { + dcmd->sgl.sge32[0].phys_addr = map_phys_addr; + dcmd->sgl.sge32[0].length = sc->current_map_sz; + } sc->map_update_cmd = cmd; if (mrsas_issue_dcmd(sc, cmd)) { @@ -3751,12 +3808,21 @@ dcmd->cmd_status = 0xFF; dcmd->sge_count = 1; dcmd->flags = MFI_FRAME_DIR_READ; + if (sizeof(bus_addr_t) == 8) + dcmd->flags |= MFI_FRAME_SGL64; dcmd->timeout = 0; dcmd->pad_0 = 0; dcmd->data_xfer_len = MRSAS_MAX_PD * sizeof(struct MR_PD_LIST); dcmd->opcode = MR_DCMD_PD_LIST_QUERY; - dcmd->sgl.sge32[0].phys_addr = pd_list_phys_addr; - dcmd->sgl.sge32[0].length = MRSAS_MAX_PD * sizeof(struct MR_PD_LIST); + if ((dcmd->flags & MFI_FRAME_SGL64) == MFI_FRAME_SGL64) { + dcmd->sgl.sge64[0].phys_addr = pd_list_phys_addr; + dcmd->sgl.sge64[0].length = MRSAS_MAX_PD * + sizeof(struct MR_PD_LIST); + } else { + dcmd->sgl.sge32[0].phys_addr = pd_list_phys_addr; + dcmd->sgl.sge32[0].length = MRSAS_MAX_PD * + sizeof(struct MR_PD_LIST); + } if (!mrsas_issue_polled(sc, cmd)) retcode = 0; @@ -3770,7 +3836,8 @@ memset(sc->local_pd_list, 0, MRSAS_MAX_PD * sizeof(struct mrsas_pd_list)); for (pd_index = 0; pd_index < pd_list_mem->count; pd_index++) { - sc->local_pd_list[pd_addr->deviceId].tid = pd_addr->deviceId; + sc->local_pd_list[pd_addr->deviceId].tid = + pd_addr->deviceId; sc->local_pd_list[pd_addr->deviceId].driveType = pd_addr->scsiDevType; sc->local_pd_list[pd_addr->deviceId].driveState = @@ -3835,11 +3902,18 @@ dcmd->cmd_status = 0xFF; dcmd->sge_count = 1; dcmd->flags = MFI_FRAME_DIR_READ; + if (sizeof(bus_addr_t) == 8) + dcmd->flags |= MFI_FRAME_SGL64; dcmd->timeout = 0; dcmd->data_xfer_len = sizeof(struct MR_LD_LIST); dcmd->opcode = MR_DCMD_LD_GET_LIST; - dcmd->sgl.sge32[0].phys_addr = ld_list_phys_addr; - dcmd->sgl.sge32[0].length = sizeof(struct MR_LD_LIST); + if ((dcmd->flags & MFI_FRAME_SGL64) == MFI_FRAME_SGL64) { + dcmd->sgl.sge64[0].phys_addr = ld_list_phys_addr; + dcmd->sgl.sge64[0].length = sizeof(struct MR_LD_LIST); + } else { + dcmd->sgl.sge32[0].phys_addr = ld_list_phys_addr; + dcmd->sgl.sge32[0].length = sizeof(struct MR_LD_LIST); + } dcmd->pad_0 = 0; if (!mrsas_issue_polled(sc, cmd)) @@ -3883,8 +3957,8 @@ { if (bus_dma_tag_create(sc->mrsas_parent_tag, 1, 0, - BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, + BUS_SPACE_MAXADDR, NULL, NULL, size, 1, @@ -4010,6 +4084,159 @@ } /* + * The timestamp is the number of seconds since 00:00 Jan 1, 2000. If + * the bits in 24-31 are all set, then it is the number of seconds since + * boot. + */ +static const char * +format_timestamp(uint32_t timestamp) +{ + static char buffer[32]; + + if ((timestamp & 0xff000000) == 0xff000000) + snprintf(buffer, sizeof(buffer), "boot + %us", timestamp & + 0x00ffffff); + else + snprintf(buffer, sizeof(buffer), "%us", timestamp); + return (buffer); +} + +static const char * +format_class(int8_t class) +{ +static char buffer[6]; + + switch (class) { + case MR_EVT_CLASS_DEBUG: + return ("debug"); + case MR_EVT_CLASS_PROGRESS: + return ("progress"); + case MR_EVT_CLASS_INFO: + return ("info"); + case MR_EVT_CLASS_WARNING: + return ("WARN"); + case MR_EVT_CLASS_CRITICAL: + return ("CRIT"); + case MR_EVT_CLASS_FATAL: + return ("FATAL"); + case MR_EVT_CLASS_DEAD: + return ("DEAD"); + default: + snprintf(buffer, sizeof(buffer), "%d", class); + return (buffer); + } +} + +static void +mrsas_decode_evt(struct mrsas_softc *sc, struct mrsas_evt_detail *detail) +{ + union mrsas_evt_class_locale class_locale; + int doscan = 0; + u_int32_t seq_num; + int error; + + device_printf(sc->mrsas_dev, "%d (%s/0x%04x/%s) - %s\n", + detail->seq_num, format_timestamp(detail->time_stamp), + detail->cl.members.locale, format_class(detail->cl.members.class), + detail->description); + + if (detail) { + switch (detail->code) { + case MR_EVT_PD_INSERTED: + mrsas_get_pd_list(sc); + mrsas_bus_scan_sim(sc, sc->sim_1); + doscan = 0; + break; + case MR_EVT_PD_REMOVED: + mrsas_get_pd_list(sc); + mrsas_bus_scan_sim(sc, sc->sim_1); + doscan = 0; + break; + case MR_EVT_LD_OFFLINE: + case MR_EVT_CFG_CLEARED: + case MR_EVT_LD_DELETED: + mrsas_bus_scan_sim(sc, sc->sim_0); + doscan = 0; + break; + case MR_EVT_LD_CREATED: + mrsas_get_ld_list(sc); + mrsas_bus_scan_sim(sc, sc->sim_0); + doscan = 0; + break; + case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED: + case MR_EVT_FOREIGN_CFG_IMPORTED: + case MR_EVT_LD_STATE_CHANGE: + doscan = 1; + break; + default: + doscan = 0; + break; + } + } else { + device_printf(sc->mrsas_dev, "invalid evt_detail\n"); + return; + } + if (doscan) { + mrsas_get_pd_list(sc); + mrsas_dprint(sc, MRSAS_AEN, "scanning ...sim 1\n"); + mrsas_bus_scan_sim(sc, sc->sim_1); + mrsas_get_ld_list(sc); + mrsas_dprint(sc, MRSAS_AEN, "scanning ...sim 0\n"); + mrsas_bus_scan_sim(sc, sc->sim_0); + } + seq_num = detail->seq_num + 1; + + /* Register AEN with FW for latest sequence number plus 1 */ + class_locale.members.reserved = 0; + class_locale.members.locale = MR_EVT_LOCALE_ALL; + class_locale.members.class = MR_EVT_CLASS_DEBUG; + + if (sc->aen_cmd != NULL) + return; + + mtx_lock(&sc->aen_lock); + error = mrsas_register_aen(sc, seq_num, + class_locale.word); + mtx_unlock(&sc->aen_lock); + + if (error) + device_printf(sc->mrsas_dev, "register aen failed error %x\n", error); +} + +static void +mrsas_handle_evt(void *context, int pending) +{ + TAILQ_HEAD(,mrsas_evt_queue_elm) queue; + struct mrsas_softc *sc; + struct mrsas_evt_queue_elm *elm; + + sc = context; + TAILQ_INIT(&queue); + mtx_lock(&sc->aen_lock); + TAILQ_CONCAT(&queue, &sc->mrsas_evt_queue, link); + mtx_unlock(&sc->aen_lock); + while ((elm = TAILQ_FIRST(&queue)) != NULL) { + TAILQ_REMOVE(&queue, elm, link); + mrsas_decode_evt(sc, &elm->detail); + free(elm, M_MRSAS); + } +} + +static void +mrsas_queue_evt(struct mrsas_softc *sc, struct mrsas_evt_detail *detail) +{ + struct mrsas_evt_queue_elm *elm; + + mtx_assert(&sc->aen_lock, MA_OWNED); + elm = malloc(sizeof(*elm), M_MRSAS, M_NOWAIT|M_ZERO); + if (elm == NULL) + return; + memcpy(&elm->detail, detail, sizeof(*detail)); + TAILQ_INSERT_TAIL(&sc->mrsas_evt_queue, elm, link); + taskqueue_enqueue(taskqueue_swi, &sc->mrsas_evt_task); +} + +/* * mrsas_aen_handler: AEN processing callback function from thread context * input: Adapter soft state * @@ -4018,15 +4245,34 @@ void mrsas_aen_handler(struct mrsas_softc *sc) { +#if 0 union mrsas_evt_class_locale class_locale; +#endif + struct mrsas_evt_detail *detail; +#if 0 int doscan = 0; u_int32_t seq_num; int error; +#endif if (!sc) { device_printf(sc->mrsas_dev, "invalid instance!\n"); return; } + + detail = sc->evt_detail_mem; + mtx_lock(&sc->aen_lock); + mrsas_queue_evt(sc, detail); + mtx_unlock(&sc->aen_lock); + + /* + device_printf(sc->mrsas_dev, "%d (%s/0x%04x/%s) - %s\n", + detail->seq_num, format_timestamp(detail->time_stamp), + detail->cl.members.locale, format_class(detail->cl.members.class), + detail->description); + */ + +#if 0 if (sc->evt_detail_mem) { switch (sc->evt_detail_mem->code) { case MR_EVT_PD_INSERTED: @@ -4088,7 +4334,7 @@ if (error) device_printf(sc->mrsas_dev, "register aen failed error %x\n", error); - +#endif } Index: mrsas.h =================================================================== --- mrsas.h (revision 295762) +++ mrsas.h (working copy) @@ -2430,6 +2430,11 @@ } __packed; +struct mrsas_evt_queue_elm { + TAILQ_ENTRY(mrsas_evt_queue_elm) link; + struct mrsas_evt_detail detail; +}; + struct mrsas_irq_context { struct mrsas_softc *sc; uint32_t MSIxIndex; @@ -2760,6 +2765,10 @@ /* Non dma-able memory. Driver local copy. */ MR_DRV_RAID_MAP_ALL *ld_drv_map[2]; + + TAILQ_HEAD(,mrsas_evt_queue_elm) mrsas_evt_queue; + struct task mrsas_evt_task; + }; /* Compatibility shims for different OS versions */ @@ -2791,4 +2800,7 @@ return ((volatile int *)p)[b >> 5] & (1 << (b & 0x1f)); } -#endif /* MRSAS_H */ +#include "mrsas_ioctl.h" +extern int mrsas_user_command(struct mrsas_softc *, struct mfi_ioc_passthru *); + +#endif /* MRSAS_H */ Index: mrsas_ioctl.c =================================================================== --- mrsas_ioctl.c (revision 295762) +++ mrsas_ioctl.c (working copy) @@ -43,6 +43,20 @@ #include #include +struct mrsas_passthru_cmd { + // struct mrsas_sge32 kern_sge32[MAX_IOCTL_SGE]; + struct iovec *kern_sge; + struct mrsas_softc *sc; + struct mrsas_mfi_cmd *cmd; + bus_dma_tag_t ioctl_data_tag; + bus_dmamap_t ioctl_data_dmamap; + + u_int32_t error_code; + u_int32_t sge_count; + int complete; +}; + + /* * Function prototypes */ @@ -62,7 +76,57 @@ mrsas_issue_blocked_cmd(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd); +#define PTRIN(p) ((void *)(uintptr_t)(p)) + /* + * mrsas_data_load_cb: Callback entry point + * input: Pointer to command packet as argument + * Pointer to segment + * Number of segments Error + * + * This is the callback function of the bus dma map load. It builds the SG + * list. + */ +static void +mrsas_passthru_load_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) +{ + struct mrsas_passthru_cmd *cb = (struct mrsas_passthru_cmd *)arg; + struct mrsas_softc *sc = cb->sc; + int i = 0; + + if (error) { + cb->error_code = error; + if (error == EFBIG) { + device_printf(sc->mrsas_dev, "mrsas_passthru_load_cb: " + "error=%d EFBIG\n", error); + cb->complete = 1; + return; + } else { + device_printf(sc->mrsas_dev, "mrsas_passthru_load_cb: " + "error=%d UNKNOWN\n", error); + } + } + if (nseg > MAX_IOCTL_SGE) { + cb->error_code = EFBIG; + device_printf(sc->mrsas_dev, "mrsas_passthru_load_cb: " + "too many segments: %d\n", nseg); + cb->complete = 1; + return; + } + + for (i = 0; i < nseg; i++) { + cb->kern_sge[i].iov_base = PTRIN(segs[i].ds_addr); + cb->kern_sge[i].iov_len = segs[i].ds_len; + } + cb->sge_count = nseg; + + bus_dmamap_sync(cb->ioctl_data_tag, cb->ioctl_data_dmamap, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + cb->complete = 1; +} + +/* * mrsas_passthru: Handle pass-through commands * input: Adapter instance soft state argument pointer * @@ -80,20 +144,24 @@ #endif union mrsas_frame *in_cmd = (union mrsas_frame *)&(user_ioc->frame.raw); struct mrsas_mfi_cmd *cmd = NULL; - bus_dma_tag_t ioctl_data_tag[MAX_IOCTL_SGE]; - bus_dmamap_t ioctl_data_dmamap[MAX_IOCTL_SGE]; - void *ioctl_data_mem[MAX_IOCTL_SGE]; - bus_addr_t ioctl_data_phys_addr[MAX_IOCTL_SGE]; + struct mrsas_passthru_cmd *passcmd = NULL; + bus_dma_tag_t ioctl_data_tag = NULL; + bus_dmamap_t ioctl_data_dmamap = NULL; bus_dma_tag_t ioctl_sense_tag = 0; bus_dmamap_t ioctl_sense_dmamap = 0; void *ioctl_sense_mem = 0; bus_addr_t ioctl_sense_phys_addr = 0; int i, ioctl_data_size = 0, ioctl_sense_size, ret = 0; - struct mrsas_sge32 *kern_sge32; + struct iovec *kern_sge; unsigned long *sense_ptr; uint8_t *iov_base_ptrin = NULL; size_t iov_len = 0; + char *ioctl_temp_data_mem; + int ioctl_temp_data_size, ioctl_remain_data_size, sge_count = 0; + ioctl_temp_data_mem = NULL; + kern_sge = NULL; + /* * Check for NOP from MegaCli... MegaCli can issue a DCMD of 0. In * this case do nothing and return 0 to it as status. @@ -115,6 +183,7 @@ device_printf(sc->mrsas_dev, "Failed to get a free cmd for IOCTL\n"); return (ENOMEM); } + /* * User's IOCTL packet has 2 frames (maximum). Copy those two frames * into our cmd's frames. cmd->frame's context will get overwritten @@ -126,7 +195,8 @@ cmd->frame->hdr.pad_0 = 0; cmd->frame->hdr.flags &= ~(MFI_FRAME_IEEE | MFI_FRAME_SGL64 | MFI_FRAME_SENSE64); - + if (sizeof(bus_addr_t) == 8) + cmd->frame->hdr.flags |= MFI_FRAME_SGL64; /* * The management interface between applications and the fw uses MFI * frames. E.g, RAID configuration changes, LD property changes etc @@ -135,98 +205,193 @@ * buffers in SGLs. The location of SGL is embedded in the struct * iocpacket itself. */ - kern_sge32 = (struct mrsas_sge32 *) - ((unsigned long)cmd->frame + user_ioc->sgl_off); + if (ioctlCmd == MRSAS_IOC_FIRMWARE_PASS_THROUGH) + kern_sge = (struct iovec *) + ((unsigned long)cmd->frame + user_ioc->sgl_off); +#ifdef COMPAT_FREEBSD32 + else { + switch (in_cmd->hdr.cmd) { + case MFI_CMD_DCMD: + kern_sge = (struct iovec *)&(cmd->frame->dcmd.sgl); + break; + case MFI_CMD_PD_SCSI_IO: + kern_sge = (struct iovec *)&(cmd->frame->pthru.sgl); + break; + default: + device_printf(sc->mrsas_dev, "Unknown command %x\n", + in_cmd->hdr.cmd); + ret = ENOMEM; + goto out; + } + } +#endif /* - * For each user buffer, create a mirror buffer and copy in + * Allocate a temporary buffer to hold the gathered input */ + ioctl_temp_data_size = 0; for (i = 0; i < user_ioc->sge_count; i++) { - if (ioctlCmd == MRSAS_IOC_FIRMWARE_PASS_THROUGH64) { + if (ioctlCmd == MRSAS_IOC_FIRMWARE_PASS_THROUGH) { if (!user_ioc->sgl[i].iov_len) continue; - ioctl_data_size = user_ioc->sgl[i].iov_len; + ioctl_temp_data_size += user_ioc->sgl[i].iov_len; #ifdef COMPAT_FREEBSD32 } else { if (!user_ioc32->sgl[i].iov_len) continue; - ioctl_data_size = user_ioc32->sgl[i].iov_len; + ioctl_temp_data_size += user_ioc32->sgl[i].iov_len; #endif } + } + + if (ioctl_temp_data_size == 0) { + kern_sge[0].iov_base = 0; + kern_sge[0].iov_len = 0; + } else { + ioctl_temp_data_mem = malloc(ioctl_temp_data_size, M_MRSAS, + M_WAITOK); + if (ioctl_temp_data_mem == NULL) { + device_printf(sc->mrsas_dev, "Could not allocate %d " + "memory for temporary passthrough ioctl\n", + ioctl_temp_data_size); + ret = ENOMEM; + goto out; + } + + /* + * For each user buffer, copy in to temp buffer + */ + ioctl_temp_data_size = 0; + for (i = 0; i < user_ioc->sge_count; i++) { + if (ioctlCmd == MRSAS_IOC_FIRMWARE_PASS_THROUGH) { + if (!user_ioc->sgl[i].iov_len) + continue; + ioctl_data_size = user_ioc->sgl[i].iov_len; +#ifdef COMPAT_FREEBSD32 + } else { + if (!user_ioc32->sgl[i].iov_len) + continue; + ioctl_data_size = user_ioc32->sgl[i].iov_len; +#endif + } + + if (ioctlCmd == MRSAS_IOC_FIRMWARE_PASS_THROUGH) { + iov_base_ptrin = user_ioc->sgl[i].iov_base; + iov_len = user_ioc->sgl[i].iov_len; +#ifdef COMPAT_FREEBSD32 + } else { + iov_base_ptrin = + PTRIN(user_ioc32->sgl[i].iov_base); + iov_len = user_ioc32->sgl[i].iov_len; +#endif + } + + /* Copy in data from user space */ + ret = copyin(iov_base_ptrin, ioctl_temp_data_mem + + ioctl_temp_data_size, iov_len); + if (ret) { + device_printf(sc->mrsas_dev, "IOCTL copyin " + "failed!\n"); + goto out; + } + ioctl_temp_data_size += iov_len; + } + + /* + * Allocate a temporary struct to hold parameters for the + * callback + */ + passcmd = malloc(sizeof(struct mrsas_passthru_cmd), M_MRSAS, + M_WAITOK); + if (passcmd == NULL) { + device_printf(sc->mrsas_dev, "Could not allocate " + "memory for temporary passthrough cb struct\n"); + ret = ENOMEM; + goto out; + } + passcmd->complete = 0; + passcmd->sc = sc; + passcmd->cmd = cmd; + passcmd->kern_sge = kern_sge; + + /* + * Create a dma tag for passthru buffers + */ if (bus_dma_tag_create(sc->mrsas_parent_tag, 1, 0, - BUS_SPACE_MAXADDR_32BIT, + BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, NULL, NULL, - ioctl_data_size, - 1, - ioctl_data_size, + ioctl_temp_data_size, + MAX_IOCTL_SGE, + ioctl_temp_data_size, BUS_DMA_ALLOCNOW, - NULL, NULL, - &ioctl_data_tag[i])) { - device_printf(sc->mrsas_dev, "Cannot allocate ioctl data tag\n"); + busdma_lock_mutex, /* lockfunc */ + &sc->ioctl_lock, /* lockarg */ + &ioctl_data_tag)) { + device_printf(sc->mrsas_dev, "Cannot allocate ioctl " + "passthru data tag\n"); ret = ENOMEM; goto out; } - if (bus_dmamem_alloc(ioctl_data_tag[i], (void **)&ioctl_data_mem[i], - (BUS_DMA_NOWAIT | BUS_DMA_ZERO), &ioctl_data_dmamap[i])) { - device_printf(sc->mrsas_dev, "Cannot allocate ioctl data mem\n"); + + /* Create memmap */ + if (bus_dmamap_create(ioctl_data_tag, 0, &ioctl_data_dmamap)) { + device_printf(sc->mrsas_dev, + "Cannot create ioctl passthru dmamap\n"); ret = ENOMEM; goto out; } - if (bus_dmamap_load(ioctl_data_tag[i], ioctl_data_dmamap[i], - ioctl_data_mem[i], ioctl_data_size, mrsas_alloc_cb, - &ioctl_data_phys_addr[i], BUS_DMA_NOWAIT)) { - device_printf(sc->mrsas_dev, "Cannot load ioctl data mem\n"); + + passcmd->ioctl_data_tag = ioctl_data_tag; + passcmd->ioctl_data_dmamap = ioctl_data_dmamap; + + /* Map data buffer into bus space */ + if (bus_dmamap_load(ioctl_data_tag, ioctl_data_dmamap, + ioctl_temp_data_mem, ioctl_temp_data_size, + mrsas_passthru_load_cb, passcmd, BUS_DMA_NOWAIT)) { + device_printf(sc->mrsas_dev, "Cannot load ioctl " + "passthru data mem %s %d\n", curproc->p_comm, ioctl_data_size); ret = ENOMEM; goto out; } - /* Save the physical address and length */ - kern_sge32[i].phys_addr = (u_int32_t)ioctl_data_phys_addr[i]; - if (ioctlCmd == MRSAS_IOC_FIRMWARE_PASS_THROUGH64) { - kern_sge32[i].length = user_ioc->sgl[i].iov_len; + while (passcmd->complete == 0) { + pause("mrsas_passthru", hz); + } - iov_base_ptrin = user_ioc->sgl[i].iov_base; - iov_len = user_ioc->sgl[i].iov_len; -#ifdef COMPAT_FREEBSD32 - } else { - kern_sge32[i].length = user_ioc32->sgl[i].iov_len; + sge_count = passcmd->sge_count; - iov_base_ptrin = PTRIN(user_ioc32->sgl[i].iov_base); - iov_len = user_ioc32->sgl[i].iov_len; -#endif - } - - /* Copy in data from user space */ - ret = copyin(iov_base_ptrin, ioctl_data_mem[i], iov_len); - if (ret) { - device_printf(sc->mrsas_dev, "IOCTL copyin failed!\n"); - goto out; - } } + + /* sense is small so it can be contigous */ + ioctl_sense_size = user_ioc->sense_len; if (user_ioc->sense_len) { if (bus_dma_tag_create(sc->mrsas_parent_tag, - 1, 0, - BUS_SPACE_MAXADDR_32BIT, + 4, 0, BUS_SPACE_MAXADDR, + BUS_SPACE_MAXADDR, NULL, NULL, ioctl_sense_size, 1, ioctl_sense_size, BUS_DMA_ALLOCNOW, - NULL, NULL, + busdma_lock_mutex, /* lockfunc */ + &sc->ioctl_lock, /* lockarg */ &ioctl_sense_tag)) { - device_printf(sc->mrsas_dev, "Cannot allocate ioctl sense tag\n"); + device_printf(sc->mrsas_dev, "Cannot allocate ioctl " + "sense tag\n"); ret = ENOMEM; goto out; } - if (bus_dmamem_alloc(ioctl_sense_tag, (void **)&ioctl_sense_mem, + if (bus_dmamem_alloc(ioctl_sense_tag, + (void **)&ioctl_sense_mem, (BUS_DMA_NOWAIT | BUS_DMA_ZERO), &ioctl_sense_dmamap)) { - device_printf(sc->mrsas_dev, "Cannot allocate ioctl sense mem\n"); + device_printf(sc->mrsas_dev, "Cannot allocate ioctl " + "sense mem\n"); ret = ENOMEM; goto out; } @@ -233,13 +398,28 @@ if (bus_dmamap_load(ioctl_sense_tag, ioctl_sense_dmamap, ioctl_sense_mem, ioctl_sense_size, mrsas_alloc_cb, &ioctl_sense_phys_addr, BUS_DMA_NOWAIT)) { - device_printf(sc->mrsas_dev, "Cannot load ioctl sense mem\n"); + device_printf(sc->mrsas_dev, "Cannot load ioctl sense " + "mem\n"); ret = ENOMEM; goto out; } - sense_ptr = - (unsigned long *)((unsigned long)cmd->frame + user_ioc->sense_off); - *sense_ptr = ioctl_sense_phys_addr; + + switch (in_cmd->hdr.cmd) { + case MFI_CMD_PD_SCSI_IO: + cmd->frame->pthru.sense_buf_phys_addr_lo = + (uint32_t)ioctl_sense_phys_addr; + cmd->frame->pthru.sense_buf_phys_addr_hi = + (uint32_t)((uint64_t)ioctl_sense_phys_addr >> + 32); + break; + default: + device_printf(sc->mrsas_dev, "Unknown command %x " + "with sense\n", in_cmd->hdr.cmd); + } + + + if (sizeof(bus_addr_t) == 8) + cmd->frame->hdr.flags |= MFI_FRAME_SENSE64; } /* * Set the sync_cmd flag so that the ISR knows not to complete this @@ -249,23 +429,45 @@ mrsas_issue_blocked_cmd(sc, cmd); cmd->sync_cmd = 0; + bus_dmamap_sync(ioctl_data_tag, ioctl_data_dmamap, + BUS_DMASYNC_POSTREAD); + /* - * copy out the kernel buffers to user buffers + * copy out the temp kernel buffers to user buffers */ - for (i = 0; i < user_ioc->sge_count; i++) { - if (ioctlCmd == MRSAS_IOC_FIRMWARE_PASS_THROUGH64) { - iov_base_ptrin = user_ioc->sgl[i].iov_base; - iov_len = user_ioc->sgl[i].iov_len; + + if (ioctl_temp_data_size != 0) { + ioctl_remain_data_size = ioctl_temp_data_size; + for (i = 0; i < user_ioc->sge_count; i++) { + if (ioctlCmd == MRSAS_IOC_FIRMWARE_PASS_THROUGH) { + iov_base_ptrin = user_ioc->sgl[i].iov_base; + iov_len = user_ioc->sgl[i].iov_len; #ifdef COMPAT_FREEBSD32 - } else { - iov_base_ptrin = PTRIN(user_ioc32->sgl[i].iov_base); - iov_len = user_ioc32->sgl[i].iov_len; + } else { + iov_base_ptrin = + PTRIN(user_ioc32->sgl[i].iov_base); + iov_len = user_ioc32->sgl[i].iov_len; #endif + } + + if (iov_len > ioctl_remain_data_size) { + iov_len = ioctl_remain_data_size; + } + + ret = copyout(ioctl_temp_data_mem + + (ioctl_temp_data_size - + ioctl_remain_data_size), iov_base_ptrin, iov_len); + if (ret) { + device_printf(sc->mrsas_dev, + "IOCTL copyout failed!\n"); + goto out; + } + ioctl_remain_data_size -= iov_len; } - ret = copyout(ioctl_data_mem[i], iov_base_ptrin, iov_len); - if (ret) { - device_printf(sc->mrsas_dev, "IOCTL copyout failed!\n"); + if (ioctl_remain_data_size != 0) { + device_printf(sc->mrsas_dev, "IOCTL copyout doesn't " + "have enough user buffers!\n"); goto out; } } @@ -278,12 +480,17 @@ * sense_buff points to the location that has the user sense * buffer address */ - sense_ptr = (unsigned long *)((unsigned long)user_ioc->frame.raw + + bus_dmamap_sync(ioctl_sense_tag, ioctl_sense_dmamap, + BUS_DMASYNC_POSTREAD); + sense_ptr = + (unsigned long *)((unsigned long)user_ioc->frame.raw + user_ioc->sense_off); - ret = copyout(ioctl_sense_mem, (unsigned long *)*sense_ptr, + ret = copyout(ioctl_sense_mem, + (unsigned long *)*sense_ptr, user_ioc->sense_len); if (ret) { - device_printf(sc->mrsas_dev, "IOCTL sense copyout failed!\n"); + device_printf(sc->mrsas_dev, "IOCTL sense copyout " + "failed!\n"); goto out; } } @@ -295,6 +502,14 @@ out: /* + * Release temporary passthrough ioctl + */ + if (ioctl_temp_data_mem) + free(ioctl_temp_data_mem, M_MRSAS); + if (passcmd) + free(passcmd, M_MRSAS); + + /* * Release sense buffer */ if (user_ioc->sense_len) { @@ -301,7 +516,8 @@ if (ioctl_sense_phys_addr) bus_dmamap_unload(ioctl_sense_tag, ioctl_sense_dmamap); if (ioctl_sense_mem != NULL) - bus_dmamem_free(ioctl_sense_tag, ioctl_sense_mem, ioctl_sense_dmamap); + bus_dmamem_free(ioctl_sense_tag, ioctl_sense_mem, + ioctl_sense_dmamap); if (ioctl_sense_tag != NULL) bus_dma_tag_destroy(ioctl_sense_tag); } @@ -308,24 +524,13 @@ /* * Release data buffers */ - for (i = 0; i < user_ioc->sge_count; i++) { - if (ioctlCmd == MRSAS_IOC_FIRMWARE_PASS_THROUGH64) { - if (!user_ioc->sgl[i].iov_len) - continue; -#ifdef COMPAT_FREEBSD32 - } else { - if (!user_ioc32->sgl[i].iov_len) - continue; -#endif - } - if (ioctl_data_phys_addr[i]) - bus_dmamap_unload(ioctl_data_tag[i], ioctl_data_dmamap[i]); - if (ioctl_data_mem[i] != NULL) - bus_dmamem_free(ioctl_data_tag[i], ioctl_data_mem[i], - ioctl_data_dmamap[i]); - if (ioctl_data_tag[i] != NULL) - bus_dma_tag_destroy(ioctl_data_tag[i]); + if (ioctl_data_dmamap != NULL) { + bus_dmamap_unload(ioctl_data_tag, ioctl_data_dmamap); + bus_dmamap_destroy(ioctl_data_tag, ioctl_data_dmamap); } + if (ioctl_data_tag != NULL) + bus_dma_tag_destroy(ioctl_data_tag); + /* Free command */ mrsas_release_mfi_cmd(cmd); @@ -332,6 +537,199 @@ return (ret); } +/** + * mrsas_user_command: Handle user mode DCMD and buffer + * input: Adapter instance soft state + * argument pointer + * + * This function is called from mrsas_ioctl() DCMDs to firmware for mfiutil + */ +int +mrsas_user_command(struct mrsas_softc *sc, struct mfi_ioc_passthru *ioc) +{ + struct mrsas_mfi_cmd *cmd; + struct mrsas_dcmd_frame *dcmd; + struct mrsas_passthru_cmd *passcmd; + bus_dma_tag_t ioctl_data_tag; + bus_dmamap_t ioctl_data_dmamap; + bus_addr_t ioctl_data_phys_addr; + struct iovec *kern_sge; + int ret, ioctl_data_size; + char *ioctl_temp_data_mem; + + ret = 0; + ioctl_temp_data_mem = NULL; + passcmd = NULL; + ioctl_data_phys_addr = 0; + dcmd = NULL; + cmd = NULL; + ioctl_data_tag = NULL; + ioctl_data_dmamap = NULL; + ioctl_data_dmamap = NULL; + + /* Get a command */ + cmd = mrsas_get_mfi_cmd(sc); + if (!cmd) { + device_printf(sc->mrsas_dev, + "Failed to get a free cmd for IOCTL\n"); + return(ENOMEM); + } + + /* + * Frame is DCMD + */ + dcmd = (struct mrsas_dcmd_frame *)cmd->frame; + memcpy(dcmd, &ioc->ioc_frame, sizeof(struct mrsas_dcmd_frame)); + + ioctl_data_size = ioc->buf_size; + + cmd->frame->hdr.context = cmd->index; + cmd->frame->hdr.pad_0 = 0; + cmd->frame->hdr.flags = MFI_FRAME_DIR_BOTH; + if (sizeof(bus_addr_t) == 8) + cmd->frame->hdr.flags |= MFI_FRAME_SGL64 | MFI_FRAME_SENSE64; + + kern_sge = (struct iovec *)(&dcmd->sgl); + + if (ioctl_data_size == 0) { + kern_sge[0].iov_base = 0; + kern_sge[0].iov_len = 0; + } else { + ioctl_temp_data_mem = malloc(ioc->buf_size, M_MRSAS, M_WAITOK); + if (ioctl_temp_data_mem == NULL) { + device_printf(sc->mrsas_dev, "Could not allocate " + "%d memory for temporary passthrough ioctl\n", + ioc->buf_size); + ret = ENOMEM; + goto out; + } + + /* Copy in data from user space */ + ret = copyin(ioc->buf, ioctl_temp_data_mem, ioc->buf_size); + if (ret) { + device_printf(sc->mrsas_dev, "IOCTL copyin failed!\n"); + goto out; + } + + /* + * Allocate a temporary struct to hold parameters for the + * callback + */ + passcmd = malloc(sizeof(struct mrsas_passthru_cmd), M_MRSAS, + M_WAITOK); + if (passcmd == NULL) { + device_printf(sc->mrsas_dev, "Could not allocate " + "memory for temporary passthrough cb struct\n"); + ret = ENOMEM; + goto out; + } + passcmd->complete = 0; + passcmd->sc = sc; + passcmd->cmd = cmd; + passcmd->kern_sge = kern_sge; + + /* + * Create a dma tag for passthru buffers + */ + if (bus_dma_tag_create(sc->mrsas_parent_tag, /* parent */ + 1, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + ioctl_data_size, /* maxsize */ + MAX_IOCTL_SGE, /* msegments */ + ioctl_data_size, /* maxsegsize */ + BUS_DMA_ALLOCNOW, /* flags */ + busdma_lock_mutex, /* lockfunc */ + &sc->ioctl_lock, /* lockarg */ + &ioctl_data_tag)) { + device_printf(sc->mrsas_dev, + "Cannot allocate ioctl data tag %d\n", + ioc->buf_size); + ret = ENOMEM; + goto out; + } + + /* Create memmap */ + if (bus_dmamap_create(ioctl_data_tag, 0, &ioctl_data_dmamap)) { + device_printf(sc->mrsas_dev, "Cannot create ioctl " + "passthru dmamap\n"); + ret = ENOMEM; + goto out; + } + + passcmd->ioctl_data_tag = ioctl_data_tag; + passcmd->ioctl_data_dmamap = ioctl_data_dmamap; + + /* Map data buffer into bus space */ + if (bus_dmamap_load(ioctl_data_tag, ioctl_data_dmamap, + ioctl_temp_data_mem, ioc->buf_size, mrsas_passthru_load_cb, + passcmd, BUS_DMA_NOWAIT)) { + device_printf(sc->mrsas_dev, "Cannot load ioctl " + "passthru data mem%s %d\n", curproc->p_comm, ioctl_data_size); + ret = ENOMEM; + goto out; + } + + while (passcmd->complete == 0) { + pause("mrsas_passthru", hz); + } + + cmd->frame->dcmd.sge_count = passcmd->sge_count; + } + + /* + * Set the sync_cmd flag so that the ISR knows not to complete this + * cmd to the SCSI mid-layer + */ + cmd->sync_cmd = 1; + mrsas_issue_blocked_cmd(sc, cmd); + cmd->sync_cmd = 0; + + if (ioctl_data_size != 0) { + bus_dmamap_sync(ioctl_data_tag, ioctl_data_dmamap, + BUS_DMASYNC_POSTREAD); + /* + * copy out the kernel buffers to user buffers + */ + ret = copyout(ioctl_temp_data_mem, ioc->buf, ioc->buf_size); + if (ret) { + device_printf(sc->mrsas_dev, + "IOCTL copyout failed!\n"); + goto out; + } + } + + /* + * Return command status to user space + */ + memcpy(&ioc->ioc_frame.cmd_status, &cmd->frame->hdr.cmd_status, + sizeof(u_int8_t)); + +out: + /* + * Release temporary passthrough ioctl + */ + if (ioctl_temp_data_mem) + free(ioctl_temp_data_mem, M_MRSAS); + if (passcmd) + free(passcmd, M_MRSAS); + + /* + * Release data buffers + */ + if (ioctl_data_phys_addr) { + bus_dmamap_unload(ioctl_data_tag, ioctl_data_dmamap); + bus_dmamap_destroy(ioctl_data_tag, ioctl_data_dmamap); + } + if (ioctl_data_tag != NULL) + bus_dma_tag_destroy(ioctl_data_tag); + /* Free command */ + mrsas_release_mfi_cmd(cmd); + + return(ret); +} + /* * mrsas_alloc_mfi_cmds: Allocates the command packets * input: Adapter instance soft state @@ -416,14 +814,15 @@ if (bus_dma_tag_create(sc->mrsas_parent_tag, 1, 0, - BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, + BUS_SPACE_MAXADDR, NULL, NULL, MRSAS_MFI_FRAME_SIZE, 1, MRSAS_MFI_FRAME_SIZE, BUS_DMA_ALLOCNOW, - NULL, NULL, + busdma_lock_mutex, /* lockfunc */ + &sc->ioctl_lock, /* lockarg */ &sc->mficmd_frame_tag)) { device_printf(sc->mrsas_dev, "Cannot create MFI frame tag\n"); return (ENOMEM); Index: mrsas_ioctl.h =================================================================== --- mrsas_ioctl.h (revision 295762) +++ mrsas_ioctl.h (working copy) @@ -65,8 +65,8 @@ * into a somewhat unique, 32-bit value. */ -#define MRSAS_IOC_GET_PCI_INFO _IOR('M', 7, MRSAS_DRV_PCI_INFORMATION) -#define MRSAS_IOC_FIRMWARE_PASS_THROUGH64 _IOWR('M', 1, struct mrsas_iocpacket) +#define MRSAS_IOC_GET_PCI_INFO _IOR('M', 7, MRSAS_DRV_PCI_INFORMATION) +#define MRSAS_IOC_FIRMWARE_PASS_THROUGH _IOWR('M', 1, struct mrsas_iocpacket) #ifdef COMPAT_FREEBSD32 #define MRSAS_IOC_FIRMWARE_PASS_THROUGH32 _IOWR('M', 1, struct mrsas_iocpacket32) #endif @@ -123,6 +123,15 @@ }; #pragma pack() -#endif /* COMPAT_FREEBSD32 */ +#endif /* COMPAT_FREEBSD32 */ -#endif /* MRSAS_IOCTL_H */ +struct mfi_ioc_passthru { + struct mrsas_dcmd_frame ioc_frame; + uint32_t pad_skinny_flag; + uint32_t buf_size; + uint8_t *buf; +} __packed; + +#define MFIIO_PASSTHRU _IOWR('C', 102, struct mfi_ioc_passthru) + +#endif /* MRSAS_IOCTL_H */