diff options
Diffstat (limited to 'sys/dev/twa/twa_freebsd.c')
-rw-r--r-- | sys/dev/twa/twa_freebsd.c | 1041 |
1 files changed, 0 insertions, 1041 deletions
diff --git a/sys/dev/twa/twa_freebsd.c b/sys/dev/twa/twa_freebsd.c deleted file mode 100644 index b153c01..0000000 --- a/sys/dev/twa/twa_freebsd.c +++ /dev/null @@ -1,1041 +0,0 @@ -/*- - * Copyright (c) 2003-04 3ware, Inc. - * Copyright (c) 2000 Michael Smith - * Copyright (c) 2000 BSDi - * All rights reserved. - * - * 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. - * - * 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. - * - * $FreeBSD$ - */ - -/* - * 3ware driver for 9000 series storage controllers. - * - * Author: Vinod Kashyap - */ - - -#include <dev/twa/twa_includes.h> - -static void twa_setup_data_dmamap(void *arg, bus_dma_segment_t *segs, - int nsegments, int error); -static void twa_setup_request_dmamap(void *arg, bus_dma_segment_t *segs, - int nsegments, int error); - -MALLOC_DEFINE(TWA_MALLOC_CLASS, "twa commands", "twa commands"); - - -static d_open_t twa_open; -static d_close_t twa_close; -static d_ioctl_t twa_ioctl_wrapper; - -static struct cdevsw twa_cdevsw = { - .d_version = D_VERSION, - .d_flags = D_NEEDGIANT, - .d_open = twa_open, - .d_close = twa_close, - .d_ioctl = twa_ioctl_wrapper, - .d_name = "twa", -}; - -static devclass_t twa_devclass; - - -/* - * Function name: twa_open - * Description: Called when the controller is opened. - * Simply marks the controller as open. - * - * Input: dev -- control device corresponding to the ctlr - * flags -- mode of open - * fmt -- device type (character/block etc.) - * proc -- current process - * Output: None - * Return value: 0 -- success - * non-zero-- failure - */ -static int -twa_open(struct cdev *dev, int flags, int fmt, d_thread_t *proc) -{ - int unit = minor(dev); - struct twa_softc *sc = devclass_get_softc(twa_devclass, unit); - - sc->twa_state |= TWA_STATE_OPEN; - return(0); -} - - - -/* - * Function name: twa_close - * Description: Called when the controller is closed. - * Simply marks the controller as not open. - * - * Input: dev -- control device corresponding to the ctlr - * flags -- mode of corresponding open - * fmt -- device type (character/block etc.) - * proc -- current process - * Output: None - * Return value: 0 -- success - * non-zero-- failure - */ -static int -twa_close(struct cdev *dev, int flags, int fmt, d_thread_t *proc) -{ - int unit = minor(dev); - struct twa_softc *sc = devclass_get_softc(twa_devclass, unit); - - sc->twa_state &= ~TWA_STATE_OPEN; - return(0); -} - - - -/* - * Function name: twa_ioctl_wrapper - * Description: Called when an ioctl is posted to the controller. - * Simply calls the ioctl handler. - * - * Input: dev -- control device corresponding to the ctlr - * cmd -- ioctl cmd - * buf -- ptr to buffer in kernel memory, which is - * a copy of the input buffer in user-space - * flags -- mode of corresponding open - * proc -- current process - * Output: buf -- ptr to buffer in kernel memory, which will - * be copied to the output buffer in user-space - * Return value: 0 -- success - * non-zero-- failure - */ -static int -twa_ioctl_wrapper(struct cdev *dev, u_long cmd, caddr_t buf, - int flags, d_thread_t *proc) -{ - struct twa_softc *sc = (struct twa_softc *)(dev->si_drv1); - - return(twa_ioctl(sc, cmd, buf)); -} - - - -static int twa_probe (device_t dev); -static int twa_attach (device_t dev); -static void twa_free (struct twa_softc *sc); -static int twa_detach (device_t dev); -static int twa_shutdown (device_t dev); -static int twa_suspend (device_t dev); -static int twa_resume (device_t dev); -static void twa_pci_intr(void *arg); - -static device_method_t twa_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, twa_probe), - DEVMETHOD(device_attach, twa_attach), - DEVMETHOD(device_detach, twa_detach), - DEVMETHOD(device_shutdown, twa_shutdown), - DEVMETHOD(device_suspend, twa_suspend), - DEVMETHOD(device_resume, twa_resume), - - DEVMETHOD(bus_print_child, bus_generic_print_child), - DEVMETHOD(bus_driver_added, bus_generic_driver_added), - {0, 0} -}; - -static driver_t twa_pci_driver = { - "twa", - twa_methods, - sizeof(struct twa_softc) -}; - -DRIVER_MODULE(twa, pci, twa_pci_driver, twa_devclass, 0, 0); - - - -/* - * Function name: twa_probe - * Description: Called at driver load time. Claims 9000 ctlrs. - * - * Input: dev -- bus device corresponding to the ctlr - * Output: None - * Return value: <= 0 -- success - * > 0 -- failure - */ -static int -twa_probe(device_t dev) -{ - static u_int8_t first_ctlr = 1; - - twa_dbg_print(3, "entered"); - - if ((pci_get_vendor(dev) == TWA_VENDOR_ID) && - (pci_get_device(dev) == TWA_DEVICE_ID_9K)) { - device_set_desc(dev, TWA_DEVICE_NAME); - /* Print the driver version only once. */ - if (first_ctlr) { - printf("3ware device driver for 9000 series storage controllers, version: %s\n", - TWA_DRIVER_VERSION_STRING); - first_ctlr = 0; - } - return(BUS_PROBE_DEFAULT); - } - return(ENXIO); -} - - - -/* - * Function name: twa_attach - * Description: Allocates pci resources; updates sc; adds a node to the - * sysctl tree to expose the driver version; makes calls - * to initialize ctlr, and to attach to CAM. - * - * Input: dev -- bus device corresponding to the ctlr - * Output: None - * Return value: 0 -- success - * non-zero-- failure - */ -static int -twa_attach(device_t dev) -{ - struct twa_softc *sc = device_get_softc(dev); - u_int32_t command; - int res_id; - int error; - - twa_dbg_dprint_enter(3, sc); - - /* Initialize the softc structure. */ - sc->twa_bus_dev = dev; - - sysctl_ctx_init(&sc->twa_sysctl_ctx); - sc->twa_sysctl_tree = SYSCTL_ADD_NODE(&sc->twa_sysctl_ctx, - SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, - device_get_nameunit(dev), CTLFLAG_RD, 0, ""); - if (sc->twa_sysctl_tree == NULL) { - twa_printf(sc, "Cannot add sysctl tree node.\n"); - return(ENXIO); - } - SYSCTL_ADD_STRING(&sc->twa_sysctl_ctx, SYSCTL_CHILDREN(sc->twa_sysctl_tree), - OID_AUTO, "driver_version", CTLFLAG_RD, - TWA_DRIVER_VERSION_STRING, 0, "TWA driver version"); - - /* Make sure we are going to be able to talk to this board. */ - command = pci_read_config(dev, PCIR_COMMAND, 2); - if ((command & PCIM_CMD_PORTEN) == 0) { - twa_printf(sc, "Register window not available.\n"); - return(ENXIO); - } - - /* Force the busmaster enable bit on, in case the BIOS forgot. */ - command |= PCIM_CMD_BUSMASTEREN; - pci_write_config(dev, PCIR_COMMAND, command, 2); - - /* Allocate the PCI register window. */ - res_id = TWA_IO_CONFIG_REG; - if ((sc->twa_io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &res_id, - 0, ~0, 1, RF_ACTIVE)) == NULL) { - twa_printf(sc, "can't allocate register window.\n"); - twa_free(sc); - return(ENXIO); - } - sc->twa_bus_tag = rman_get_bustag(sc->twa_io_res); - sc->twa_bus_handle = rman_get_bushandle(sc->twa_io_res); - - /* Initialize the driver for this controller. */ - if ((error = twa_setup(sc))) { - twa_free(sc); - return(error); - } - - /* Print some information about the controller and configuration. */ - twa_describe_controller(sc); - - /* Allocate and connect our interrupt. */ - res_id = 0; - if ((sc->twa_irq_res = bus_alloc_resource(sc->twa_bus_dev, SYS_RES_IRQ, - &res_id, 0, ~0, 1, - RF_SHAREABLE | RF_ACTIVE)) == NULL) { - twa_printf(sc, "Can't allocate interrupt.\n"); - twa_free(sc); - return(ENXIO); - } - if (bus_setup_intr(sc->twa_bus_dev, sc->twa_irq_res, INTR_TYPE_CAM, - twa_pci_intr, sc, &sc->twa_intr_handle)) { - twa_printf(sc, "Can't set up interrupt.\n"); - twa_free(sc); - return(ENXIO); - } - - /* Create the control device. */ - sc->twa_ctrl_dev = make_dev(&twa_cdevsw, device_get_unit(sc->twa_bus_dev), - UID_ROOT, GID_OPERATOR, S_IRUSR | S_IWUSR, - "twa%d", device_get_unit(sc->twa_bus_dev)); - sc->twa_ctrl_dev->si_drv1 = sc; - - if ((error = twa_cam_setup(sc))) { - twa_free(sc); - return(error); - } - return(0); -} - - - -/* - * Function name: twa_free - * Description: Performs clean-up at the time of going down. - * - * Input: sc -- ptr to per ctlr structure - * Output: None - * Return value: None - */ -static void -twa_free(struct twa_softc *sc) -{ - struct twa_request *tr; - - twa_dbg_dprint_enter(3, sc); - - /* Detach from CAM */ - twa_cam_detach(sc); - - /* Destroy dma handles. */ - - bus_dmamap_unload(sc->twa_cmd_tag, sc->twa_cmd_map); - while ((tr = twa_dequeue_free(sc)) != NULL) - bus_dmamap_destroy(sc->twa_buf_tag, tr->tr_buf_map); - - /* Free all memory allocated so far. */ - if (sc->twa_req_buf) - free(sc->twa_req_buf, TWA_MALLOC_CLASS); - if (sc->twa_cmd_pkt_buf) - bus_dmamem_free(sc->twa_cmd_tag, sc->twa_cmd_pkt_buf, - sc->twa_cmd_map); - if (sc->twa_aen_queue[0]) - free(sc->twa_aen_queue[0], M_DEVBUF); - - /* Destroy the data-transfer DMA tag. */ - if (sc->twa_buf_tag) - bus_dma_tag_destroy(sc->twa_buf_tag); - - /* Destroy the cmd DMA tag. */ - if (sc->twa_cmd_tag) - bus_dma_tag_destroy(sc->twa_cmd_tag); - - /* Destroy the parent DMA tag. */ - if (sc->twa_parent_tag) - bus_dma_tag_destroy(sc->twa_parent_tag); - - /* Disconnect the interrupt handler. */ - if (sc->twa_intr_handle) - bus_teardown_intr(sc->twa_bus_dev, sc->twa_irq_res, - sc->twa_intr_handle); - if (sc->twa_irq_res != NULL) - bus_release_resource(sc->twa_bus_dev, SYS_RES_IRQ, - 0, sc->twa_irq_res); - - /* Release the register window mapping. */ - if (sc->twa_io_res != NULL) - bus_release_resource(sc->twa_bus_dev, SYS_RES_IOPORT, - TWA_IO_CONFIG_REG, sc->twa_io_res); - - /* Destroy the control device. */ - if (sc->twa_ctrl_dev != (struct cdev *)NULL) - destroy_dev(sc->twa_ctrl_dev); - - sysctl_ctx_free(&sc->twa_sysctl_ctx); -} - - - -/* - * Function name: twa_detach - * Description: Called when the controller is being detached from - * the pci bus. - * - * Input: dev -- bus device corresponding to the ctlr - * Output: None - * Return value: 0 -- success - * non-zero-- failure - */ -static int -twa_detach(device_t dev) -{ - struct twa_softc *sc = device_get_softc(dev); - int s; - int error; - - twa_dbg_dprint_enter(3, sc); - - error = EBUSY; - s = splcam(); - if (sc->twa_state & TWA_STATE_OPEN) - goto out; - - /* Shut the controller down. */ - if ((error = twa_shutdown(dev))) - goto out; - - /* Free all resources associated with this controller. */ - twa_free(sc); - error = 0; - -out: - splx(s); - return(error); -} - - - -/* - * Function name: twa_shutdown - * Description: Called at unload/shutdown time. Lets the controller - * know that we are going down. - * - * Input: dev -- bus device corresponding to the ctlr - * Output: None - * Return value: 0 -- success - * non-zero-- failure - */ -static int -twa_shutdown(device_t dev) -{ - struct twa_softc *sc = device_get_softc(dev); - int s; - int error = 0; - - twa_dbg_dprint_enter(3, sc); - - s = splcam(); - - /* Disconnect from the controller. */ - error = twa_deinit_ctlr(sc); - - splx(s); - return(error); -} - - - -/* - * Function name: twa_suspend - * Description: Called to suspend I/O before hot-swapping PCI ctlrs. - * Doesn't do much as of now. - * - * Input: dev -- bus device corresponding to the ctlr - * Output: None - * Return value: 0 -- success - * non-zero-- failure - */ -static int -twa_suspend(device_t dev) -{ - struct twa_softc *sc = device_get_softc(dev); - int s; - - twa_dbg_dprint_enter(3, sc); - - s = splcam(); - sc->twa_state |= TWA_STATE_SUSPEND; - - twa_disable_interrupts(sc); - splx(s); - - return(1); -} - - - -/* - * Function name: twa_resume - * Description: Called to resume I/O after hot-swapping PCI ctlrs. - * Doesn't do much as of now. - * - * Input: dev -- bus device corresponding to the ctlr - * Output: None - * Return value: 0 -- success - * non-zero-- failure - */ -static int -twa_resume(device_t dev) -{ - struct twa_softc *sc = device_get_softc(dev); - - twa_dbg_dprint_enter(3, sc); - - sc->twa_state &= ~TWA_STATE_SUSPEND; - twa_enable_interrupts(sc); - - return(1); -} - - - -/* - * Function name: twa_pci_intr - * Description: Interrupt handler. Wrapper for twa_interrupt. - * - * Input: arg -- ptr to per ctlr structure - * Output: None - * Return value: None - */ -static void -twa_pci_intr(void *arg) -{ - struct twa_softc *sc = (struct twa_softc *)arg; - - twa_interrupt(sc); -} - - - -/* - * Function name: twa_write_pci_config - * Description: Writes to the PCI config space. - * - * Input: sc -- ptr to per ctlr structure - * value -- value to be written - * size -- # of bytes to be written - * Output: None - * Return value: None - */ -void -twa_write_pci_config(struct twa_softc *sc, u_int32_t value, int size) -{ - pci_write_config(sc->twa_bus_dev, PCIR_STATUS, value, size); -} - - - -/* - * Function name: twa_alloc_req_pkts - * Description: Allocates memory for, and initializes request pkts, - * and queues them in the free queue. - * - * Input: sc -- ptr to per ctlr structure - * num_reqs-- # of request pkts to allocate and initialize. - * Output: None - * Return value: 0 -- success - * non-zero-- failure - */ -int -twa_alloc_req_pkts(struct twa_softc *sc, int num_reqs) -{ - struct twa_request *tr; - int i; - - if ((sc->twa_req_buf = malloc(num_reqs * sizeof(struct twa_request), - TWA_MALLOC_CLASS, M_NOWAIT)) == NULL) - return(ENOMEM); - - /* Create the parent dma tag. */ - if (bus_dma_tag_create(NULL, /* parent */ - TWA_ALIGNMENT, /* alignment */ - 0, /* boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - TWA_Q_LENGTH * - (sizeof(struct twa_command_packet)),/* maxsize */ - TWA_MAX_SG_ELEMENTS, /* nsegments */ - BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ - 0, /* flags */ - NULL, /* lockfunc */ - NULL, /* lockfuncarg */ - &sc->twa_parent_tag /* tag */)) { - twa_printf(sc, "Can't allocate parent DMA tag.\n"); - return(ENOMEM); - } - - /* Create a bus dma tag for cmd pkts. */ - if (bus_dma_tag_create(sc->twa_parent_tag, /* parent */ - TWA_ALIGNMENT, /* alignment */ - 0, /* boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - TWA_Q_LENGTH * - (sizeof(struct twa_command_packet)),/* maxsize */ - 1, /* nsegments */ - BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ - 0, /* flags */ - NULL, /* lockfunc */ - NULL, /* lockfuncarg */ - &sc->twa_cmd_tag /* tag */)) { - twa_printf(sc, "Can't allocate cmd DMA tag.\n"); - return(ENOMEM); - } - - - /* Allocate memory for cmd pkts. */ - if (bus_dmamem_alloc(sc->twa_cmd_tag, - (void *)(&(sc->twa_cmd_pkt_buf)), - BUS_DMA_WAITOK, &(sc->twa_cmd_map))) { - twa_printf(sc, "Can't allocate memory for cmd pkts.\n"); - return(ENOMEM); - } - - bus_dmamap_load(sc->twa_cmd_tag, sc->twa_cmd_map, - sc->twa_cmd_pkt_buf, - num_reqs * sizeof(struct twa_command_packet), - twa_setup_request_dmamap, sc, 0); - bzero(sc->twa_req_buf, num_reqs * sizeof(struct twa_request)); - bzero(sc->twa_cmd_pkt_buf, - num_reqs * sizeof(struct twa_command_packet)); - - /* Create a bus dma tag for data buffers. */ - if (bus_dma_tag_create(sc->twa_parent_tag, /* parent */ - TWA_ALIGNMENT, /* alignment */ - 0, /* boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - TWA_MAX_IO_SIZE, /* maxsize */ - TWA_MAX_SG_ELEMENTS, /* nsegments */ - TWA_MAX_IO_SIZE, /* maxsegsize */ - BUS_DMA_ALLOCNOW, /* flags */ - busdma_lock_mutex, /* lockfunc */ - &Giant, /* lockfuncarg */ - &sc->twa_buf_tag /* tag */)) { - twa_printf(sc, "Can't allocate buf DMA tag.\n"); - return(ENOMEM); - } - - for (i = 0; i < num_reqs; i++) { - tr = &(sc->twa_req_buf[i]); - tr->tr_command = &(sc->twa_cmd_pkt_buf[i]); - tr->tr_cmd_phys = sc->twa_cmd_pkt_phys + - (i * sizeof(struct twa_command_packet)); - tr->tr_request_id = i; - tr->tr_sc = sc; - sc->twa_lookup[i] = tr; - - /* Create maps for data buffers. */ - if (bus_dmamap_create(sc->twa_buf_tag, 0, - &tr->tr_buf_map)) - return(ENOMEM); - - /* Insert request into the free queue. */ - twa_release_request(tr); - } - return(0); -} - - - -/* - * Function name: twa_fillin_sgl - * Description: Fills in the scatter/gather list. - * - * Input: sgl -- ptr to sg list - * segs -- ptr to fill the sg list from - * nsegments--# of segments - * Output: None - * Return value: None - */ -static void -twa_fillin_sgl(struct twa_sg *sgl, bus_dma_segment_t *segs, int nsegments) -{ - int i; - - for (i = 0; i < nsegments; i++) { - sgl[i].address = segs[i].ds_addr; - sgl[i].length = (u_int32_t)(segs[i].ds_len); - } -} - - - -/* - * Function name: twa_setup_data_dmamap - * Description: Callback of bus_dmamap_load for the buffer associated - * with data. Updates the cmd pkt (size/sgl_entries - * fields, as applicable) to reflect the number of sg - * elements. - * - * Input: arg -- ptr to request pkt - * segs -- ptr to a list of segment descriptors - * nsegments--# of segments - * error -- 0 if no errors encountered before callback, - * non-zero if errors were encountered - * Output: None - * Return value: None - */ -static void -twa_setup_data_dmamap(void *arg, bus_dma_segment_t *segs, - int nsegments, int error) -{ - struct twa_request *tr = (struct twa_request *)arg; - struct twa_command_packet *cmdpkt = tr->tr_command; - struct twa_command_9k *cmd9k; - union twa_command_7k *cmd7k; - u_int8_t sgl_offset; - - twa_dbg_dprint_enter(10, tr->tr_sc); - - tr->tr_flags |= TWA_CMD_MAPPED; - if ((tr->tr_flags & TWA_CMD_IN_PROGRESS) && - (tr->tr_cmd_pkt_type & TWA_CMD_PKT_TYPE_EXTERNAL)) - twa_allow_new_requests(tr->tr_sc, (void *)(tr->tr_private)); - - if (error == EFBIG) { - tr->tr_error = error; - goto out; - } - - if (tr->tr_cmd_pkt_type & TWA_CMD_PKT_TYPE_9K) { - cmd9k = &(cmdpkt->command.cmd_pkt_9k); - twa_fillin_sgl(&(cmd9k->sg_list[0]), segs, nsegments); - cmd9k->sgl_entries += nsegments - 1; - } else { - /* It's a 7000 command packet. */ - cmd7k = &(cmdpkt->command.cmd_pkt_7k); - if ((sgl_offset = cmdpkt->command.cmd_pkt_7k.generic.sgl_offset)) - twa_fillin_sgl((struct twa_sg *) - (((u_int32_t *)cmd7k) + sgl_offset), - segs, nsegments); - /* Modify the size field, based on sg address size. */ - cmd7k->generic.size += - ((TWA_64BIT_ADDRESSES ? 3 : 2) * nsegments); - } - - if (tr->tr_flags & TWA_CMD_DATA_IN) - bus_dmamap_sync(tr->tr_sc->twa_buf_tag, tr->tr_buf_map, - BUS_DMASYNC_PREREAD); - if (tr->tr_flags & TWA_CMD_DATA_OUT) { - /* - * If we're using an alignment buffer, and we're - * writing data, copy the real data out. - */ - if (tr->tr_flags & TWA_CMD_DATA_COPY_NEEDED) - bcopy(tr->tr_real_data, tr->tr_data, tr->tr_real_length); - bus_dmamap_sync(tr->tr_sc->twa_buf_tag, tr->tr_buf_map, - BUS_DMASYNC_PREWRITE); - } - error = twa_submit_io(tr); - -out: - if (error) { - twa_unmap_request(tr); - /* - * If the caller had been returned EINPROGRESS, and he has - * registered a callback for handling completion, the callback - * will never get called because we were unable to submit the - * request. So, free up the request right here. - */ - if ((tr->tr_flags & TWA_CMD_IN_PROGRESS) && (tr->tr_callback)) - twa_release_request(tr); - } -} - - - -/* - * Function name: twa_setup_request_dmamap - * Description: Callback of bus_dmamap_load for the buffer associated - * with a cmd pkt. - * - * Input: arg -- ptr to request pkt - * segs -- ptr to a list of segment descriptors - * nsegments--# of segments - * error -- 0 if no errors encountered before callback, - * non-zero if errors were encountered - * Output: None - * Return value: None - */ -static void -twa_setup_request_dmamap(void *arg, bus_dma_segment_t *segs, - int nsegments, int error) -{ - struct twa_softc *sc = (struct twa_softc *)arg; - - twa_dbg_dprint_enter(10, sc); - - sc->twa_cmd_pkt_phys = segs[0].ds_addr; -} - - - -/* - * Function name: twa_map_request - * Description: Maps a cmd pkt and data associated with it, into - * DMA'able memory. - * - * Input: tr -- ptr to request pkt - * Output: None - * Return value: 0 -- success - * non-zero-- failure - */ -int -twa_map_request(struct twa_request *tr) -{ - struct twa_softc *sc = tr->tr_sc; - int error = 0; - - twa_dbg_dprint_enter(10, sc); - - /* If the command involves data, map that too. */ - if (tr->tr_data != NULL) { - /* - * It's sufficient for the data pointer to be 4-byte aligned - * to work with 9000. However, if 4-byte aligned addresses - * are passed to bus_dmamap_load, we can get back sg elements - * that are not 512-byte multiples in size. So, we will let - * only those buffers that are 512-byte aligned to pass - * through, and bounce the rest, so as to make sure that we - * always get back sg elements that are 512-byte multiples - * in size. - */ - if (((vm_offset_t)tr->tr_data % 512) || (tr->tr_length % 512)) { - tr->tr_flags |= TWA_CMD_DATA_COPY_NEEDED; - tr->tr_real_data = tr->tr_data; /* save original data pointer */ - tr->tr_real_length = tr->tr_length; /* save original data length */ - tr->tr_length = (tr->tr_length + 511) & ~511; - tr->tr_data = malloc(tr->tr_length, TWA_MALLOC_CLASS, M_NOWAIT); - if (tr->tr_data == NULL) { - twa_printf(sc, "%s: malloc failed\n", __func__); - tr->tr_data = tr->tr_real_data; /* restore original data pointer */ - tr->tr_length = tr->tr_real_length; /* restore original data length */ - return(ENOMEM); - } - } - - /* - * Map the data buffer into bus space and build the s/g list. - */ - if ((error = bus_dmamap_load(sc->twa_buf_tag, tr->tr_buf_map, - tr->tr_data, - (bus_size_t)(tr->tr_length), - twa_setup_data_dmamap, tr, - BUS_DMA_WAITOK))) { - if (error == EINPROGRESS) { - int s; - - s = splcam(); - if (!(tr->tr_flags & TWA_CMD_MAPPED)) { - tr->tr_flags |= TWA_CMD_IN_PROGRESS; - if (tr->tr_cmd_pkt_type & TWA_CMD_PKT_TYPE_EXTERNAL) - twa_disallow_new_requests(sc); - } - splx(s); - error = 0; - } else { - /* Free alignment buffer if it was used. */ - if (tr->tr_flags & TWA_CMD_DATA_COPY_NEEDED) { - free(tr->tr_data, TWA_MALLOC_CLASS); - tr->tr_data = tr->tr_real_data; /* restore 'real' data pointer */ - tr->tr_length = tr->tr_real_length;/* restore 'real' data length */ - } - } - } else - error = tr->tr_error; - - } else - if ((error = twa_submit_io(tr))) - twa_unmap_request(tr); - - return(error); -} - - - -/* - * Function name: twa_unmap_request - * Description: Undoes the mapping done by twa_map_request. - * - * Input: tr -- ptr to request pkt - * Output: None - * Return value: None - */ -void -twa_unmap_request(struct twa_request *tr) -{ - struct twa_softc *sc = tr->tr_sc; - u_int8_t cmd_status; - - twa_dbg_dprint_enter(10, sc); - - /* If the command involved data, unmap that too. */ - if (tr->tr_data != NULL) { - if (tr->tr_cmd_pkt_type & TWA_CMD_PKT_TYPE_9K) - cmd_status = tr->tr_command->command.cmd_pkt_9k.status; - else - cmd_status = tr->tr_command->command.cmd_pkt_7k.generic.status; - - if (tr->tr_flags & TWA_CMD_DATA_IN) { - bus_dmamap_sync(sc->twa_buf_tag, - tr->tr_buf_map, BUS_DMASYNC_POSTREAD); - - /* - * If we are using a bounce buffer, and we are reading - * data, copy the real data in. - */ - if (tr->tr_flags & TWA_CMD_DATA_COPY_NEEDED) - if (cmd_status == 0) - bcopy(tr->tr_data, tr->tr_real_data, - tr->tr_real_length); - } - if (tr->tr_flags & TWA_CMD_DATA_OUT) - bus_dmamap_sync(sc->twa_buf_tag, tr->tr_buf_map, - BUS_DMASYNC_POSTWRITE); - - bus_dmamap_unload(sc->twa_buf_tag, tr->tr_buf_map); - } - - /* Free alignment buffer if it was used. */ - if (tr->tr_flags & TWA_CMD_DATA_COPY_NEEDED) { - free(tr->tr_data, TWA_MALLOC_CLASS); - tr->tr_data = tr->tr_real_data; /* restore 'real' data pointer */ - tr->tr_length = tr->tr_real_length;/* restore 'real' data length */ - } -} - - - -#ifdef TWA_DEBUG -void twa_report(void); -void twa_reset_stats(void); -void twa_print_request(struct twa_request *tr, int req_type); - - - -/* - * Function name: twa_report - * Description: For being called from ddb. Prints controller stats, - * and requests, if any, that are in the wrong queue. - * - * Input: None - * Output: None - * Return value: None - */ -void -twa_report(void) -{ - struct twa_softc *sc; - struct twa_request *tr; - int s; - int i; - - s = splcam(); - for (i = 0; (sc = devclass_get_softc(twa_devclass, i)) != NULL; i++) { - twa_print_controller(sc); - TAILQ_FOREACH(tr, &sc->twa_busy, tr_link) - twa_print_request(tr, TWA_CMD_BUSY); - TAILQ_FOREACH(tr, &sc->twa_complete, tr_link) - twa_print_request(tr, TWA_CMD_COMPLETE); - } - splx(s); -} - - - -/* - * Function name: twa_reset_stats - * Description: For being called from ddb. - * Resets some controller stats. - * - * Input: None - * Output: None - * Return value: None - */ -void -twa_reset_stats(void) -{ - struct twa_softc *sc; - int s; - int i; - - s = splcam(); - for (i = 0; (sc = devclass_get_softc(twa_devclass, i)) != NULL; i++) { - sc->twa_qstats[TWAQ_FREE].q_max = 0; - sc->twa_qstats[TWAQ_BUSY].q_max = 0; - sc->twa_qstats[TWAQ_PENDING].q_max = 0; - sc->twa_qstats[TWAQ_COMPLETE].q_max = 0; - } - splx(s); -} - - - -/* - * Function name: twa_print_request - * Description: Prints a given request if it's in the wrong queue. - * - * Input: tr -- ptr to request pkt - * req_type-- expected status of the given request - * Output: None - * Return value: None - */ -void -twa_print_request(struct twa_request *tr, int req_type) -{ - struct twa_softc *sc = tr->tr_sc; - struct twa_command_packet *cmdpkt = tr->tr_command; - struct twa_command_9k *cmd9k; - union twa_command_7k *cmd7k; - u_int8_t *cdb; - - if (tr->tr_status != req_type) { - twa_printf(sc, "Invalid %s request %p in queue! req_type = %x, queue_type = %x\n", - (tr->tr_cmd_pkt_type & TWA_CMD_PKT_TYPE_INTERNAL) ? "INTERNAL" : "EXTERNAL", - tr, tr->tr_status, req_type); - - if (tr->tr_cmd_pkt_type & TWA_CMD_PKT_TYPE_9K) { - cmd9k = &(cmdpkt->command.cmd_pkt_9k); - twa_printf(sc, "9K cmd = %x %x %x %x %x %x %x %jx %x\n", - cmd9k->command.opcode, - cmd9k->command.reserved, - cmd9k->unit, - cmd9k->request_id, - cmd9k->status, - cmd9k->sgl_offset, - cmd9k->sgl_entries, - (uintmax_t)(cmd9k->sg_list[0].address), - cmd9k->sg_list[0].length); - cdb = (u_int8_t *)(cmdpkt->command.cmd_pkt_9k.cdb); - twa_printf(sc, "cdb = %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n", - cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], - cdb[8], cdb[9], cdb[10], cdb[11], cdb[12], cdb[13], cdb[14], cdb[15]); - } else { - cmd7k = &(cmdpkt->command.cmd_pkt_7k); - twa_printf(sc, "7K cmd = %x %x %x %x %x %x %x %x %x\n", - cmd7k->generic.opcode, - cmd7k->generic.sgl_offset, - cmd7k->generic.size, - cmd7k->generic.request_id, - cmd7k->generic.unit, - cmd7k->generic.host_id, - cmd7k->generic.status, - cmd7k->generic.flags, - cmd7k->generic.count); - } - - twa_printf(sc, "cmd_phys=0x%jx data=%p length=0x%x\n", - (uintmax_t)(tr->tr_cmd_phys), tr->tr_data, - tr->tr_length); - twa_printf(sc, "req_id=0x%x flags=0x%x callback=%p private=%p\n", - tr->tr_request_id, tr->tr_flags, - tr->tr_callback, tr->tr_private); - } -} -#endif |