--- /home/attilio/FreeBSD/STABLE_7/sys/dev/aac/aac.c 2010-02-22 17:03:24.000000000 +0100 +++ /home/attilio/aac.c 2010-02-26 15:35:45.000000000 +0100 @@ -3175,8 +3174,376 @@ out: static int aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg) { - return (EINVAL); + struct aac_command *cm; + struct aac_fib *fib; + struct aac_event *event; + struct aac_srb32 *srbcmd, *usrb; + struct aac_sg_entry *sge; + struct aac_sg_entry64 *sge64; + void *srb_sg_address; + uint32_t fibsize, srb_sg_bytecount; + int error, i; + + usrb = (struct aac_srb32 *)arg; + cm = NULL; + + fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); + + printf("AAC: Entering aac_ioctl_send_raw_srb()\n"); + mtx_lock(&sc->aac_io_lock); + if (aac_alloc_command(sc, &cm)) { + event = malloc(sizeof(struct aac_event), M_AACBUF, + M_NOWAIT | M_ZERO); + if (event == NULL) { + mtx_unlock(&sc->aac_io_lock); + error = EBUSY; + goto out; + } + event->ev_type = AAC_EVENT_CMFREE; + event->ev_callback = aac_ioctl_event; + event->ev_arg = &cm; + aac_add_event(sc, event); + msleep(cm, &sc->aac_io_lock, 0, "aacraw", 0); + } + mtx_unlock(&sc->aac_io_lock); + + cm->cm_data = NULL; + fib = cm->cm_fib; + srbcmd = (struct aac_srb32 *)fib->data; + error = copyin(&usrb->data_len, &fibsize, sizeof(uint32_t)); + if (error != 0) + goto out; + if (fibsize > (sc->aac_max_fib_size - sizeof(struct aac_fib_header))) { + error = EINVAL; + goto out; + } + error = copyin(usrb, srbcmd, fibsize); + if (error != 0) + goto out; + srbcmd->function = 0; + srbcmd->retry_limit = 0; + if (srbcmd->sg_map32.SgCount > 1) { + error = EINVAL; + goto out; + } + + /* Retrieve correct SG entries. */ + if (fibsize == (sizeof(struct aac_srb32) + + srbcmd->sg_map32.SgCount * sizeof(struct aac_sg_entry))) { + sge = srbcmd->sg_map32.SgEntry; + sge64 = NULL; + srb_sg_bytecount = sge->SgByteCount; +#ifdef __amd64__ + srb_sg_address = (void *)(uint64_t)sge->SgAddress; +#else + srb_sg_address = (void *)sge->SgAddress; +#endif + } +#ifdef __amd64__ + else if (fibsize == (sizeof(struct aac_srb64) + + srbcmd->sg_map32.SgCount * sizeof(struct aac_sg_entry64))) { + sge = NULL; + sge64 = (struct aac_sg_entry64 *)srbcmd->sg_map32.SgEntry; + srb_sg_bytecount = sge64->SgByteCount; + srb_sg_address = (void *)sge64->SgAddress; + if (sge64->SgAddress > 0xffffffffull && + (sc->flags & AAC_FLAGS_SG_64BIT) == 0) { + error = EINVAL; + goto out; + } + } +#endif + else { + error = EINVAL; + goto out; + } + + /* Setup the FIB and the command. */ + fib->Header.Size = sizeof(struct aac_fib_header) + + sizeof(struct aac_srb32); + fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | + AAC_FIBSTATE_INITIALISED | AAC_FIBSTATE_EMPTY | + AAC_FIBSTATE_FROMHOST | AAC_FIBSTATE_REXPECTED | + AAC_FIBSTATE_NORM | AAC_FIBSTATE_ASYNC | + AAC_FIBSTATE_FAST_RESPONSE; + fib->Header.Command = (sc->flags & AAC_FLAGS_SG_64BIT) ? + ScsiPortCommandU64 : ScsiPortCommand; + + srbcmd->data_len = srb_sg_bytecount; + cm->cm_sgtable = (struct aac_sg_table *)&srbcmd->sg_map32; + printf("AAC: srbcmd->sg_map32.SgCount: %d\n", + srbcmd->sg_map32.SgCount); + if (srbcmd->sg_map32.SgCount == 1) { + cm->cm_datalen = srb_sg_bytecount; + cm->cm_data = malloc(cm->cm_datalen, M_AACBUF, M_NOWAIT); + if (cm->cm_data == NULL) { + error = ENOMEM; + goto out; + } + printf("AAC: cm->cm_datalen: %u, srbcmd->flags: 0x%x\n", + cm->cm_datalen, srbcmd->flags); + if (srbcmd->flags & AAC_SRB_FLAGS_DATA_IN) + cm->cm_flags |= AAC_CMD_DATAIN; + if (srbcmd->flags & AAC_SRB_FLAGS_DATA_OUT) { + cm->cm_flags |= AAC_CMD_DATAOUT; + error = copyin(srb_sg_address, cm->cm_data, + cm->cm_datalen); + if (error != 0) + goto out; + } + } + mtx_lock(&sc->aac_io_lock); + aac_wait_command(cm); + mtx_unlock(&sc->aac_io_lock); + + if (srbcmd->sg_map32.SgCount == 1 && + (srbcmd->flags & AAC_SRB_FLAGS_DATA_IN) != 0) { + printf("AAC: Starting of the cm->cm_data payload:\n"); + for (i = 0; i < cm->cm_datalen; i++) + printf("0x%x ", ((char *)cm->cm_data)[i]); + printf("\n"); + error = copyout(cm->cm_data, srb_sg_address, cm->cm_datalen); + if (error != 0) + goto out; + } + printf("AAC: Starting of the fib->data payload:\n"); + for (i = 0; i < sizeof(struct aac_srb_response); i++) + printf("0x%x ", ((char *)fib->data)[i]); + printf("\n"); + error = copyout(fib->data, usrb + fibsize, + sizeof(struct aac_srb_response)); +out: + if (cm != NULL) { + if (cm->cm_data != NULL) + free(cm->cm_data, M_AACBUF); + mtx_lock(&sc->aac_io_lock); + aac_release_command(cm); + mtx_unlock(&sc->aac_io_lock); + } + printf("ERROR: %d\n", error); + return (error); +} + +#if 0 +static int +aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg) +{ + struct aac_command *cm; + struct aac_fib *fib; + struct aac_srb32 *srbcmd; + struct aac_srb32 *user_srb = (struct aac_srb32 *)arg; + void *user_reply; + int error, transfer_data = 0; + bus_dmamap_t orig_map = 0; + u_int32_t fibsize = 0; + u_int64_t srb_sg_address; + u_int32_t srb_sg_bytecount; + int i; + + fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); + + cm = NULL; + + printf("AAC: Entering aac_ioctl_send_raw_srb()\n"); + mtx_lock(&sc->aac_io_lock); + if (aac_alloc_command(sc, &cm)) { + struct aac_event *event; + + event = malloc(sizeof(struct aac_event), M_AACBUF, + M_NOWAIT | M_ZERO); + if (event == NULL) { + error = EBUSY; + mtx_unlock(&sc->aac_io_lock); + goto out; + } + event->ev_type = AAC_EVENT_CMFREE; + event->ev_callback = aac_ioctl_event; + event->ev_arg = &cm; + aac_add_event(sc, event); + msleep(cm, &sc->aac_io_lock, 0, "sndraw", 0); + } + mtx_unlock(&sc->aac_io_lock); + + cm->cm_data = NULL; + /* save original dma map */ + orig_map = cm->cm_datamap; + + fib = cm->cm_fib; + srbcmd = (struct aac_srb32 *)fib->data; + if ((error = copyin((void *)&user_srb->data_len, &fibsize, + sizeof (u_int32_t)) != 0)) + goto out; + if (fibsize > (sc->aac_max_fib_size-sizeof(struct aac_fib_header))) { + error = EINVAL; + goto out; + } + if ((error = copyin((void *)user_srb, srbcmd, fibsize) != 0)) + goto out; + + srbcmd->function = 0; /* SRBF_ExecuteScsi */ + srbcmd->retry_limit = 0; /* obsolete */ + + /* only one sg element from userspace supported */ + if (srbcmd->sg_map32.SgCount > 1) { + error = EINVAL; + goto out; + } + /* check fibsize */ + if (fibsize == (sizeof(struct aac_srb32) + + srbcmd->sg_map32.SgCount * sizeof(struct aac_sg_entry))) { + struct aac_sg_entry *sgp = srbcmd->sg_map32.SgEntry; + srb_sg_bytecount = sgp->SgByteCount; + srb_sg_address = (u_int64_t)sgp->SgAddress; + } else if (fibsize == (sizeof(struct aac_srb32) + + srbcmd->sg_map32.SgCount * sizeof(struct aac_sg_entry64))) { +#ifdef __amd64__ + struct aac_sg_entry64 *sgp = + (struct aac_sg_entry64 *)srbcmd->sg_map32.SgEntry; + srb_sg_bytecount = sgp->SgByteCount; + srb_sg_address = sgp->SgAddress; + if (srb_sg_address > 0xffffffffull && + !(sc->flags & AAC_FLAGS_SG_64BIT)) +#endif + { + error = EINVAL; + goto out; + } + } else { + error = EINVAL; + goto out; + } + user_reply = (char *)arg + fibsize; + srbcmd->data_len = srb_sg_bytecount; + printf("AAC: srbcmd->sg_map32.SgCount: %d\n", + srbcmd->sg_map32.SgCount); + if (srbcmd->sg_map32.SgCount == 1) + transfer_data = 1; + + if (transfer_data) { + /* + * Create DMA tag for the passthr. data buffer and allocate it. + */ + if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ + 1, 0, /* algnmnt, boundary */ + (sc->flags & AAC_FLAGS_SG_64BIT) ? + BUS_SPACE_MAXADDR_32BIT : + 0x7fffffff, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + srb_sg_bytecount, /* size */ + sc->aac_sg_tablesize, /* nsegments */ + srb_sg_bytecount, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* No locking needed */ + &cm->cm_passthr_dmat)) { + error = ENOMEM; + goto out; + } + if (bus_dmamem_alloc(cm->cm_passthr_dmat, (void **)&cm->cm_data, + BUS_DMA_NOWAIT, &cm->cm_datamap)) { + error = ENOMEM; + goto out; + } + /* fill some cm variables */ + cm->cm_datalen = srb_sg_bytecount; + printf("AAC: cm->cm_datalen: %u, srbcmd->flags: 0x%x\n", + cm->cm_datalen, srbcmd->flags); + if (srbcmd->flags & AAC_SRB_FLAGS_DATA_IN) + cm->cm_flags |= AAC_CMD_DATAIN; + if (srbcmd->flags & AAC_SRB_FLAGS_DATA_OUT) + cm->cm_flags |= AAC_CMD_DATAOUT; + + if (srbcmd->flags & AAC_SRB_FLAGS_DATA_OUT) { + if ((error = copyin( +#ifdef __amd64__ + (void *)srb_sg_address, +#else + (void *)(u_int32_t)srb_sg_address, +#endif + cm->cm_data, cm->cm_datalen)) != 0) + goto out; + /* sync required for bus_dmamem_alloc() alloc. mem.? */ + bus_dmamap_sync(cm->cm_passthr_dmat, cm->cm_datamap, + BUS_DMASYNC_PREWRITE); + } + } + + /* build the FIB */ + fib->Header.Size = sizeof(struct aac_fib_header) + + sizeof(struct aac_srb32); + fib->Header.XferState = + AAC_FIBSTATE_HOSTOWNED | + AAC_FIBSTATE_INITIALISED | + AAC_FIBSTATE_EMPTY | + AAC_FIBSTATE_FROMHOST | + AAC_FIBSTATE_REXPECTED | + AAC_FIBSTATE_NORM | + AAC_FIBSTATE_ASYNC | + AAC_FIBSTATE_FAST_RESPONSE; + + fib->Header.Command = (sc->flags & AAC_FLAGS_SG_64BIT) ? + ScsiPortCommandU64 : ScsiPortCommand; + cm->cm_sgtable = (struct aac_sg_table *)&srbcmd->sg_map32; + + /* send command */ + if (transfer_data) { + bus_dmamap_load(cm->cm_passthr_dmat, + cm->cm_datamap, cm->cm_data, + cm->cm_datalen, + aac_map_command_sg, cm, 0); + } else { + aac_map_command_sg(cm, NULL, 0, 0); + } + + /* wait for completion */ + mtx_lock(&sc->aac_io_lock); + while (!(cm->cm_flags & AAC_CMD_COMPLETED)) + msleep(cm, &sc->aac_io_lock, 0, "sndrw2", 0); + mtx_unlock(&sc->aac_io_lock); + + /* copy data */ + if (transfer_data && (srbcmd->flags & AAC_SRB_FLAGS_DATA_IN)) { + printf("AAC: Starting of the cm->cm_data payload:\n"); + for (i = 0; i < cm->cm_datalen; i++) + printf("0x%x ", ((char *)cm->cm_data)[i]); + printf("\n"); + if ((error = copyout(cm->cm_data, +#ifdef __amd64__ + (void *)srb_sg_address, +#else + (void *)(u_int32_t)srb_sg_address, +#endif + cm->cm_datalen)) != 0) + goto out; + /* sync required for bus_dmamem_alloc() allocated mem.? */ + bus_dmamap_sync(cm->cm_passthr_dmat, cm->cm_datamap, + BUS_DMASYNC_POSTREAD); + } + + printf("AAC: Starting of the fib->data payload:\n"); + for (i = 0; i < sizeof(struct aac_srb_response); i++) + printf("0x%x ", ((char *)fib->data)[i]); + printf("\n"); + + /* status */ + error = copyout(fib->data, user_reply, sizeof(struct aac_srb_response)); + +out: + if (cm && cm->cm_data) { + if (transfer_data) + bus_dmamap_unload(cm->cm_passthr_dmat, cm->cm_datamap); + bus_dmamem_free(cm->cm_passthr_dmat, cm->cm_data, cm->cm_datamap); + cm->cm_datamap = orig_map; + } + if (cm && cm->cm_passthr_dmat) + bus_dma_tag_destroy(cm->cm_passthr_dmat); + if (cm) { + mtx_unlock(&sc->aac_io_lock); + } + printf("ERROR: %d\n", error); + return(error); } +#endif /* * Handle an AIF sent to us by the controller; queue it for later reference.