Page MenuHomeFreeBSD

D36342.id109806.diff
No OneTemporary

D36342.id109806.diff

diff --git a/sys/dev/mrsas/mrsas.h b/sys/dev/mrsas/mrsas.h
--- a/sys/dev/mrsas/mrsas.h
+++ b/sys/dev/mrsas/mrsas.h
@@ -3660,4 +3660,7 @@
return ((volatile int *)p)[b >> 5] & (1 << (b & 0x1f));
}
+#include "mrsas_ioctl.h"
+extern int mrsas_user_command(struct mrsas_softc *, struct mfi_ioc_passthru *);
+
#endif /* MRSAS_H */
diff --git a/sys/dev/mrsas/mrsas.c b/sys/dev/mrsas/mrsas.c
--- a/sys/dev/mrsas/mrsas.c
+++ b/sys/dev/mrsas/mrsas.c
@@ -1449,7 +1449,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;
@@ -1512,6 +1519,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;
diff --git a/sys/dev/mrsas/mrsas_ioctl.h b/sys/dev/mrsas/mrsas_ioctl.h
--- a/sys/dev/mrsas/mrsas_ioctl.h
+++ b/sys/dev/mrsas/mrsas_ioctl.h
@@ -124,4 +124,13 @@
#pragma pack()
#endif /* COMPAT_FREEBSD32 */
+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 */
diff --git a/sys/dev/mrsas/mrsas_ioctl.c b/sys/dev/mrsas/mrsas_ioctl.c
--- a/sys/dev/mrsas/mrsas_ioctl.c
+++ b/sys/dev/mrsas/mrsas_ioctl.c
@@ -43,6 +43,18 @@
#include <dev/mrsas/mrsas.h>
#include <dev/mrsas/mrsas_ioctl.h>
+struct mrsas_passthru_cmd {
+ 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,6 +74,54 @@
mrsas_issue_blocked_cmd(struct mrsas_softc *sc,
struct mrsas_mfi_cmd *cmd);
+/*
+ * 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
@@ -344,6 +404,200 @@
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

File Metadata

Mime Type
text/plain
Expires
Thu, Apr 23, 9:36 AM (15 h, 22 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
32022298
Default Alt Text
D36342.id109806.diff (8 KB)

Event Timeline