diff options
Diffstat (limited to 'sys/dev/ic/mpt_openbsd.c')
-rw-r--r-- | sys/dev/ic/mpt_openbsd.c | 1578 |
1 files changed, 0 insertions, 1578 deletions
diff --git a/sys/dev/ic/mpt_openbsd.c b/sys/dev/ic/mpt_openbsd.c deleted file mode 100644 index 4bfb5da3276..00000000000 --- a/sys/dev/ic/mpt_openbsd.c +++ /dev/null @@ -1,1578 +0,0 @@ -/* $OpenBSD: mpt_openbsd.c,v 1.33 2006/04/20 20:29:56 miod Exp $ */ -/* $NetBSD: mpt_netbsd.c,v 1.7 2003/07/14 15:47:11 lukem Exp $ */ - -/* - * Copyright (c) 2004 Milos Urbanek - * 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. - */ - -/* - * Copyright (c) 2003 Wasabi Systems, Inc. - * All rights reserved. - * - * Written by Jason R. Thorpe for Wasabi Systems, Inc. - * - * 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. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed for the NetBSD Project by - * Wasabi Systems, Inc. - * 4. The name of Wasabi Systems, Inc. may not be used to endorse - * or promote products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC - * 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. - */ - -/* - * Copyright (c) 2000, 2001 by Greg Ansley - * Partially derived from Matt Jacob's ISP driver. - * - * 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 immediately at the beginning of the file, without modification, - * this list of conditions, and the following disclaimer. - * 2. The name of the author may not 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. - */ -/* - * Additional Copyright (c) 2002 by Matthew Jacob under same license. - */ - -/* - * mpt_openbsd.c: - * - * OpenBSD-specific routines for LSI Fusion adapters. Includes some - * bus_dma glue, and SCSI glue. - * - * Adapted from the NetBSD "mpt" driver by Milos Urbanek for - * ZOOM International, s.r.o. - */ - -#include <sys/cdefs.h> -/* __KERNEL_RCSID(0, "$NetBSD: mpt_netbsd.c,v 1.7 2003/07/14 15:47:11 lukem Exp $"); */ - -#include <dev/ic/mpt.h> /* pulls in all headers */ - -void mpt_run_ppr(struct mpt_softc *, int); -int mpt_ppr(struct mpt_softc *, struct scsi_link *, int, int); -int mpt_poll(struct mpt_softc *, struct scsi_xfer *, int); -void mpt_timeout(void *); -void mpt_done(struct mpt_softc *, uint32_t); -int mpt_run_xfer(struct mpt_softc *, struct scsi_xfer *); -void mpt_check_xfer_settings(struct mpt_softc *, struct scsi_xfer *, MSG_SCSI_IO_REQUEST *); -void mpt_ctlop(struct mpt_softc *, void *vmsg, uint32_t); -void mpt_event_notify_reply(struct mpt_softc *, MSG_EVENT_NOTIFY_REPLY *); - -int mpt_action(struct scsi_xfer *); -void mpt_minphys(struct buf *); - -struct cfdriver mpt_cd = { - NULL, "mpt", DV_DULL -}; - -/* the below structure is so we have a default dev struct for our link struct */ -static struct scsi_device mpt_dev = { - NULL, /* Use default error handler */ - NULL, /* have a queue, served by this */ - NULL, /* have no async handler */ - NULL, /* Use default 'done' routine */ -}; - -enum mpt_scsi_speed { U320, U160, U80 }; - -/* - * try speed and - * return 0 if failed - * return 1 if passed - */ -int -mpt_ppr(struct mpt_softc *mpt, struct scsi_link *sc_link, int speed, int flags) -{ - CONFIG_PAGE_SCSI_DEVICE_0 page0; - CONFIG_PAGE_SCSI_DEVICE_1 page1; - uint8_t tp; - int error; - struct scsi_inquiry_data inqbuf; - - DNPRINTF(30, "Entering PPR\n"); - - if (mpt->is_fc) { - /* - * SCSI transport settings don't make any sense for - * Fibre Channel; silently ignore the request. - */ - return 1; /* success */ - } - - /* - * Always allow disconnect; we don't have a way to disable - * it right now, in any case. - */ - mpt->mpt_disc_enable |= (1 << sc_link->target); - - /* - * Enable tagged queueing. - */ - if (sc_link->quirks & SDEV_NOTAGS) - mpt->mpt_tag_enable &= ~(1 << sc_link->target); - else - mpt->mpt_tag_enable |= (1 << sc_link->target); - - page1 = mpt->mpt_dev_page1[sc_link->target]; - - /* - * Set the wide/narrow parameter for the target. - */ - if (sc_link->quirks & SDEV_NOWIDE) - page1.RequestedParameters &= ~MPI_SCSIDEVPAGE1_RP_WIDE; - else { - page1.RequestedParameters |= MPI_SCSIDEVPAGE1_RP_WIDE; - } - - /* - * Set the synchronous parameters for the target. - */ - page1.RequestedParameters &= - ~(MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK | - MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK | - MPI_SCSIDEVPAGE1_RP_DT | MPI_SCSIDEVPAGE1_RP_QAS | - MPI_SCSIDEVPAGE1_RP_IU); - - if (!(sc_link->quirks & SDEV_NOSYNC)) { - int factor, offset, np; - - /* - * Factor: - * 0x08 = U320 = 6.25ns - * 0x09 = U160 = 12.5ns - * 0x0a = U80 = 25ns - */ - factor = (mpt->mpt_port_page0.Capabilities >> 8) & 0xff; - offset = (mpt->mpt_port_page0.Capabilities >> 16) & 0xff; - np = 0; - - switch (speed) { - case U320: - /* do nothing */ - break; - - case U160: - factor = 0x09; /* force U160 */ - break; - - case U80: - factor = 0x0a; /* force U80 */ - } - - if (factor < 0x9) { - /* Ultra320 enable QAS & IU */ - np |= MPI_SCSIDEVPAGE1_RP_QAS | MPI_SCSIDEVPAGE1_RP_IU; - } - if (factor < 0xa) { - /* >= Ultra160 enable DT transfer */ - np |= MPI_SCSIDEVPAGE1_RP_DT; - } - np |= (factor << 8) | (offset << 16); - page1.RequestedParameters |= np; - } - - /* write parameters out to chip */ - if (mpt_write_cfg_page(mpt, sc_link->target, &page1.Header)) { - mpt_prt(mpt, "unable to write Device Page 1"); - return 0; - } - - /* make sure the parameters were written */ - if (mpt_read_cfg_page(mpt, sc_link->target, &page1.Header)) { - mpt_prt(mpt, "unable to read back Device Page 1"); - return 0; - } - - mpt->mpt_dev_page1[sc_link->target] = page1; - - DNPRINTF(30, - "%s: SPI Target %d Page 1: RequestedParameters %x Config %x\n", - DEVNAME(mpt), - sc_link->target, - mpt->mpt_dev_page1[sc_link->target].RequestedParameters, - mpt->mpt_dev_page1[sc_link->target].Configuration); - - /* - * use INQUIRY for PPR two reasons: - * 1) actually transfer data at requested speed - * 2) no need to test for TUR QUIRK - */ - error = scsi_inquire(sc_link, &inqbuf, flags); - if (error) { - mpt_prt(mpt, "Invalid INQUIRY on target: %d", sc_link->target); - return 0; - } - - /* read page 0 back to figure out if the PPR worked */ - page0 = mpt->mpt_dev_page0[sc_link->target]; - if (mpt_read_cfg_page(mpt, sc_link->target, &page0.Header)) { - mpt_prt(mpt, "unable to read Device Page 0"); - return 0; - } - - DNPRINTF(30, - "%s: SPI Tgt %d Page 0: NParms %x Information %x\n", - DEVNAME(mpt), - sc_link->target, - page0.NegotiatedParameters, page0.Information); - - if (!(page0.NegotiatedParameters & 0x07) && (speed == U320)) { - /* - * if lowest 3 aren't set the PPR probably failed, - * retry with other parameters - */ - DNPRINTF(30, "%s: U320 PPR failed\n", DEVNAME(mpt)); - return 0; - } - - if ((((page0.NegotiatedParameters >> 8) & 0xff) > 0x09) && - (speed == U160)) { - /* if transfer period > 0x09 then U160 PPR failed, retry */ - DNPRINTF(30, "%s: U160 PPR failed\n", DEVNAME(mpt)); - return 0; - } - - /* - * Bit 3 - PPR rejected: IOC sets this if the device rejects PPR. - * Bit 2 - WDTR rejected: IOC sets this if the device rejects WDTR. - * Bit 1 - SDTR Rejected: IOC sets this if the device rejects SDTR. - * Bit 0 - 1 A SCSI SDTR, WDTR, or PPR negotiation has occurred. - */ - if (page0.Information & 0x0e) { - /* target rejected PPR message */ - mpt_prt(mpt, "Target %d rejected PPR message with %02x", - sc_link->target, - (uint8_t)page0.Information); - - return 0; - } - - /* print PPR results */ - switch ((page0.NegotiatedParameters >> 8) & 0xff) { - case 0x08: - tp = 160; - break; - - case 0x09: - tp = 80; - break; - - case 0x0a: - tp = 40; - break; - - case 0x0b: - tp = 20; - break; - - case 0x0c: - tp = 10; - break; - - default: - tp = 0; - } - - mpt_prt(mpt, - "target %d %s at %dMHz width %dbit offset %d QAS %d DT %d IU %d", - sc_link->target, - tp ? "Synchronous" : "Asynchronous", - tp, - (page0.NegotiatedParameters & 0x20000000) ? 16 : 8, - (page0.NegotiatedParameters >> 16) & 0xff, - (page0.NegotiatedParameters & 0x04) ? 1 : 0, - (page0.NegotiatedParameters & 0x02) ? 1 : 0, - (page0.NegotiatedParameters & 0x01) ? 1 : 0); - - return 1; /* success */ -} - -/* - * Run PPR on all attached devices - */ -void -mpt_run_ppr(struct mpt_softc *mpt, int flags) -{ - struct scsi_link *sc_link; - struct device *dev; - u_int8_t target; - u_int16_t buswidth; - - /* walk device list */ - for (dev = TAILQ_FIRST(&alldevs); dev != NULL; - dev = TAILQ_NEXT(dev, dv_list)) { - if (dev->dv_parent == (struct device *)mpt) { - /* found scsibus softc */ - buswidth = ((struct scsi_link *)&mpt->sc_link)-> - adapter_buswidth; - /* printf("mpt_softc: %x scsibus: %x buswidth: %d\n", - * mpt, dev, buswidth); */ - /* walk target list */ - for (target = 0; target < buswidth; target++) { - sc_link = ((struct scsibus_softc *)dev)-> - sc_link[target][0]; - if ((sc_link != NULL)) { - /* got a device! run PPR */ - /* skip CPU devices since they - * can crash at U320 speeds */ - if ((sc_link->inqdata.device & SID_TYPE) - == T_PROCESSOR) { - continue; - } - if (mpt_ppr(mpt, sc_link, U320, flags)){ - mpt->mpt_negotiated_speed - [target] = U320; - continue; - } - - if (mpt_ppr(mpt, sc_link, U160, flags)){ - mpt->mpt_negotiated_speed - [target] = U160; - continue; - } - - if (mpt_ppr(mpt, sc_link, U80, flags)) { - mpt->mpt_negotiated_speed - [target] = U80; - continue; - } - } /* sc_link */ - } /* for target */ - } /* if dev */ - } /* end for dev */ -} - -/* - * Complete attachment of hardware, include subdevices. - */ -void -mpt_attach(struct mpt_softc *mpt) -{ - struct scsi_link *lptr = &mpt->sc_link; - - mpt->bus = 0; /* XXX ?? */ - - /* Fill in the scsi_adapter. */ - mpt->sc_adapter.scsi_cmd = mpt_action; - mpt->sc_adapter.scsi_minphys = mpt_minphys; - - /* Fill in the prototype scsi_link */ - lptr->adapter_softc = mpt; - lptr->device = &mpt_dev; - lptr->adapter = &mpt->sc_adapter; - lptr->flags = 0; - lptr->luns = 8; - - if (mpt->is_fc) { - lptr->adapter_buswidth = 256; - lptr->adapter_target = 256; - } else { - lptr->adapter_buswidth = 16; - lptr->adapter_target = mpt->mpt_ini_id; - } - lptr->openings = MPT_MAX_REQUESTS(mpt) / lptr->adapter_buswidth; - - DNPRINTF(10, "%s: IM support: %x\n", DEVNAME(mpt), mpt->im_support); - - (void) config_found(&mpt->mpt_dev, lptr, scsiprint); - - /* done attaching now walk targets and PPR them */ - /* FC does not do PPR */ - if (!mpt->is_fc) { - mpt_run_ppr(mpt, SCSI_POLL); - } -} - -int -mpt_dma_mem_alloc(struct mpt_softc *mpt) -{ - bus_dma_segment_t reply_seg, request_seg; - int reply_rseg, request_rseg; - bus_addr_t pptr, end; - caddr_t vptr; - size_t len; - int error, i; - - /* Check if we have already allocated the reply memory. */ - if (mpt->reply != NULL) - return (0); - - /* - * Allocate the request pool. This isn't really DMA'd memory, - * but it's a convenient place to do it. - */ - len = sizeof(struct req_entry) * MPT_MAX_REQUESTS(mpt); - mpt->request_pool = malloc(len, M_DEVBUF, M_WAITOK); - if (mpt->request_pool == NULL) { - printf("%s: unable to allocate request pool\n", - mpt->mpt_dev.dv_xname); - return (ENOMEM); - } - bzero(mpt->request_pool, len); - - /* - * Allocate DMA resources for reply buffers. - */ - error = bus_dmamap_create(mpt->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE, - 0, 0, &mpt->reply_dmap); - if (error) { - printf("%s: unable to create reply DMA map, error = %d\n", - mpt->mpt_dev.dv_xname, error); - goto free_request_pool; - } - - error = bus_dmamem_alloc(mpt->sc_dmat, PAGE_SIZE, PAGE_SIZE, 0, - &reply_seg, 1, &reply_rseg, 0); - if (error) { - printf("%s: unable to allocate reply area, error = %d\n", - mpt->mpt_dev.dv_xname, error); - goto destroy_reply; - } - - error = bus_dmamem_map(mpt->sc_dmat, &reply_seg, reply_rseg, PAGE_SIZE, - (caddr_t *) &mpt->reply, BUS_DMA_COHERENT/*XXX*/); - if (error) { - printf("%s: unable to map reply area, error = %d\n", - mpt->mpt_dev.dv_xname, error); - goto free_reply; - } - - error = bus_dmamap_load(mpt->sc_dmat, mpt->reply_dmap, mpt->reply, - PAGE_SIZE, NULL, 0); - if (error) { - printf("%s: unable to load reply DMA map, error = %d\n", - mpt->mpt_dev.dv_xname, error); - goto unmap_reply; - } - - /* - * Allocate DMA resources for request buffers. - */ - error = bus_dmamap_create(mpt->sc_dmat, MPT_REQ_MEM_SIZE(mpt), 1, - MPT_REQ_MEM_SIZE(mpt), 0, 0, &mpt->request_dmap); - if (error) { - printf("%s: unable to create request DMA map, error = %d\n", - mpt->mpt_dev.dv_xname, error); - goto unload_reply; - } - - error = bus_dmamem_alloc(mpt->sc_dmat, MPT_REQ_MEM_SIZE(mpt), - PAGE_SIZE, 0, &request_seg, 1, &request_rseg, 0); - if (error) { - printf("%s: unable to allocate request area, error = %d\n", - mpt->mpt_dev.dv_xname, error); - goto destroy_request; - } - - error = bus_dmamem_map(mpt->sc_dmat, &request_seg, request_rseg, - MPT_REQ_MEM_SIZE(mpt), (caddr_t *) &mpt->request, 0); - if (error) { - printf("%s: unable to map request area, error = %d\n", - mpt->mpt_dev.dv_xname, error); - goto free_request; - } - - error = bus_dmamap_load(mpt->sc_dmat, mpt->request_dmap, mpt->request, - MPT_REQ_MEM_SIZE(mpt), NULL, 0); - if (error) { - printf("%s: unable to load request DMA map, error = %d\n", - mpt->mpt_dev.dv_xname, error); - goto unmap_request; - } - - pptr = mpt->request_dmap->dm_segs[0].ds_addr; - vptr = (caddr_t) mpt->request; - end = pptr + MPT_REQ_MEM_SIZE(mpt); - - for (i = 0; pptr < end; i++) { - struct req_entry *req = &mpt->request_pool[i]; - req->index = i; - - /* Store location of Request Data */ - req->req_pbuf = pptr; - req->req_vbuf = vptr; - - pptr += MPT_REQUEST_AREA; - vptr += MPT_REQUEST_AREA; - - req->sense_pbuf = (pptr - MPT_SENSE_SIZE); - req->sense_vbuf = (vptr - MPT_SENSE_SIZE); - - error = bus_dmamap_create(mpt->sc_dmat, MAXPHYS, - MPT_SGL_MAX, MAXPHYS, 0, 0, &req->dmap); - if (error) { - printf("%s: unable to create req %d DMA map, error = " - "%d", mpt->mpt_dev.dv_xname, i, error); - goto unload_request; - } - } - - mpt->request_phys = mpt->request_dmap->dm_segs[0].ds_addr; - mpt->reply_phys = mpt->reply_dmap->dm_segs[0].ds_addr; - return (0); - -unload_request: - for (--i; i >= 0; i--) { - struct req_entry *req = &mpt->request_pool[i]; - if (req->dmap != NULL) - bus_dmamap_destroy(mpt->sc_dmat, req->dmap); - } - bus_dmamap_unload(mpt->sc_dmat, mpt->request_dmap); -unmap_request: - bus_dmamem_unmap(mpt->sc_dmat, (caddr_t)mpt->request, PAGE_SIZE); -free_request: - bus_dmamem_free(mpt->sc_dmat, &request_seg, 1); -destroy_request: - bus_dmamap_destroy(mpt->sc_dmat, mpt->request_dmap); - -unload_reply: - bus_dmamap_unload(mpt->sc_dmat, mpt->reply_dmap); -unmap_reply: - bus_dmamem_unmap(mpt->sc_dmat, (caddr_t)mpt->reply, PAGE_SIZE); -free_reply: - bus_dmamem_free(mpt->sc_dmat, &reply_seg, 1); -destroy_reply: - bus_dmamap_destroy(mpt->sc_dmat, mpt->reply_dmap); - -free_request_pool: - free(mpt->request_pool, M_DEVBUF); - - mpt->reply = NULL; - mpt->request = NULL; - mpt->request_pool = NULL; - - return (error); -} - -int -mpt_intr(void *arg) -{ - struct mpt_softc *mpt = arg; - int nrepl = 0; - uint32_t reply; - - /* - if ((mpt_read(mpt, MPT_OFFSET_INTR_STATUS) & MPT_INTR_REPLY_READY) == 0) - return (0); - */ - - /* - * Speed up trick to save one PCI read. - * Reply FIFO replies 0xffffffff whenever - * MPT_OFFSET_INTR_STATUS & MPT_INTR_REPLY_READY == 0 - * - */ - - reply = mpt_pop_reply_queue(mpt); - - if (reply == 0xffffffff) { - /* check doorbell, this is error path not IO path */ - /* FIXME for now ignore strays and doorbells */ - return (0); - } - - while (reply != MPT_REPLY_EMPTY) { - nrepl++; -#ifdef MPT_DEBUG - if (mpt_debug > 50) { - if ((reply & MPT_CONTEXT_REPLY) != 0) - /* Address reply; IOC has something to say */ - mpt_print_reply(MPT_REPLY_PTOV(mpt, reply)); - else - /* Context reply; all went well */ - mpt_prt(mpt, "context %u reply OK", reply); - } -#endif /* MPT_DEBUG */ - mpt_done(mpt, reply); - reply = mpt_pop_reply_queue(mpt); - } - return (nrepl != 0); -} - -void -mpt_prt(struct mpt_softc *mpt, const char *fmt, ...) -{ - va_list ap; - - printf("%s: ", mpt->mpt_dev.dv_xname); - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); - printf("\n"); -} - -int -mpt_poll(struct mpt_softc *mpt, struct scsi_xfer *xs, int count) -{ - - /* Timeouts are in msec, so we loop in 1000usec cycles */ - while (count) { - mpt_intr(mpt); - if (xs->flags & ITSDONE) { - return (0); - } - delay(1000); /* only happens in boot, so ok */ - count--; - } - return (1); -} - -void -mpt_timeout(void *arg) -{ - struct req_entry *req = arg; - struct scsi_xfer *xs = req->xfer; - struct scsi_link *linkp = xs->sc_link; - struct mpt_softc *mpt = (void *) linkp->adapter_softc; - uint32_t oseq; - int s, index; - - mpt_prt(mpt, "command timeout"); - sc_print_addr(linkp); - - s = splbio(); - - oseq = req->sequence; - mpt->timeouts++; - if (mpt_intr(mpt)) { - if (req->sequence != oseq) { - mpt_prt(mpt, "recovered from command timeout"); - splx(s); - return; - } - } - mpt_prt(mpt, - "timeout on request index = 0x%x, seq = 0x%08x", - req->index, req->sequence); - mpt_check_doorbell(mpt); - mpt_prt(mpt, "Status 0x%08x, Mask 0x%08x, Doorbell 0x%08x", - mpt_read(mpt, MPT_OFFSET_INTR_STATUS), - mpt_read(mpt, MPT_OFFSET_INTR_MASK), - mpt_read(mpt, MPT_OFFSET_DOORBELL)); -#ifdef MPT_DEBUG - mpt_prt(mpt, "request state: %s", mpt_req_state(req->debug)); - mpt_print_scsi_io_request((MSG_SCSI_IO_REQUEST *)req->req_vbuf); -#else - mpt_prt(mpt, "request state: %i", req->debug); -#endif /* MPT_DEBUG */ - - for(index = 0; index < MPT_MAX_REQUESTS(mpt); index++) - if (req == &mpt->request_pool[index]) { - req->debug = REQ_TIMEOUT; - break; - } - - mpt_done(mpt, index); - - splx(s); -} - -void -mpt_done(struct mpt_softc *mpt, uint32_t reply) -{ - struct scsi_xfer *xs = NULL; - struct scsi_link *linkp; - int index; - struct req_entry *req; - MSG_REQUEST_HEADER *mpt_req; - MSG_SCSI_IO_REPLY *mpt_reply; - - - if ((reply & MPT_CONTEXT_REPLY) == 0) { - /* context reply (ok) */ - mpt_reply = NULL; - index = reply & MPT_CONTEXT_MASK; - } else { - /* address reply (error) */ - - /* XXX BUS_DMASYNC_POSTREAD XXX */ - mpt_reply = MPT_REPLY_PTOV(mpt, reply); -#ifdef MPT_DEBUG - if (mpt_debug > 50) { - uint32_t *pReply = (uint32_t *) mpt_reply; - - mpt_prt(mpt, "Address Reply (index %u):", - mpt_reply->MsgContext & 0xffff); - mpt_prt(mpt, "%08x %08x %08x %08x", - pReply[0], pReply[1], pReply[2], pReply[3]); - mpt_prt(mpt, "%08x %08x %08x %08x", - pReply[4], pReply[5], pReply[6], pReply[7]); - mpt_prt(mpt, "%08x %08x %08x %08x", - pReply[8], pReply[9], pReply[10], pReply[11]); - } -#endif /* MPT_DEBUG */ - index = mpt_reply->MsgContext; - } - - /* - * Address reply with MessageContext high bit set. - * This is most likely a notify message, so we try - * to process it, then free it. - */ - if ((index & 0x80000000) != 0) { - if (mpt_reply != NULL) - mpt_ctlop(mpt, mpt_reply, reply); - else - mpt_prt(mpt, "mpt_done: index 0x%x, NULL reply", index); - return; - } - - /* Did we end up with a valid index into the table? */ - if (index < 0 || index >= MPT_MAX_REQUESTS(mpt)) { - mpt_prt(mpt, "mpt_done: invalid index (0x%x) in reply", index); - return; - } - - req = &mpt->request_pool[index]; - - /* Make sure memory hasn't been trashed. */ - if (req->index != index) { - mpt_prt(mpt, "mpt_done: corrupted struct req_entry (0x%x)", index); - return; - } - - MPT_SYNC_REQ(mpt, req, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); - mpt_req = req->req_vbuf; - - /* Short cut for task management replies; nothing more for us to do. */ - if (mpt_req->Function == MPI_FUNCTION_SCSI_TASK_MGMT) { - DNPRINTF(50, "%s: mpt_done: TASK MGMT\n", DEVNAME(mpt)); - goto done; - } - - if (mpt_req->Function == MPI_FUNCTION_PORT_ENABLE) - goto done; - - /* - * At this point, it had better be a SCSI I/O command, but don't - * crash if it isn't. - */ - if (mpt_req->Function != MPI_FUNCTION_SCSI_IO_REQUEST) { - DNPRINTF(10, "%s: mpt_done: unknown Function 0x%x (0x%x)\n", - DEVNAME(mpt), mpt_req->Function, index); - goto done; - } - - /* Recover scsi_xfer from the request structure. */ - xs = req->xfer; - - /* Can't have a SCSI command without a scsi_xfer. */ - if (xs == NULL) { - mpt_prt(mpt, - "mpt_done: no scsi_xfer, index = 0x%x, seq = 0x%08x", - req->index, req->sequence); -#ifdef MPT_DEBUG - mpt_prt(mpt, "request state: %s", mpt_req_state(req->debug)); - mpt_prt(mpt, "mpt_request:"); - mpt_print_scsi_io_request((MSG_SCSI_IO_REQUEST *)req->req_vbuf); -#else - mpt_prt(mpt, "request state: %i", req->debug); -#endif /* MPT_DEBUG */ - - if (mpt_reply != NULL) { -#ifdef MPT_DEBUG - mpt_prt(mpt, "mpt_reply:"); - mpt_print_reply(mpt_reply); -#endif /* MPT_DEBUG */ - } else { - mpt_prt(mpt, "context reply: 0x%08x", reply); - } - goto done; - } - - timeout_del(&xs->stimeout); - - linkp = xs->sc_link; - - /* - * If we were a data transfer, unload the map that described - * the data buffer. - */ - if (xs->datalen != 0) { - bus_dmamap_sync(mpt->sc_dmat, req->dmap, 0, - req->dmap->dm_mapsize, - (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD - : BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(mpt->sc_dmat, req->dmap); - } - - if (req->debug == REQ_TIMEOUT) { - xs->error = XS_TIMEOUT; - xs->status = SCSI_OK; - xs->resid = 0; - goto done; - } else if (mpt_reply == NULL) { - /* - * Context reply; report that the command was - * successful! - * - * Also report the xfer mode, if necessary. - */ - xs->error = XS_NOERROR; - xs->status = SCSI_OK; - xs->resid = 0; - goto done; - } - - xs->status = mpt_reply->SCSIStatus; - switch (mpt_reply->IOCStatus) { - case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: - xs->error = XS_DRIVER_STUFFUP; - break; - - case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: - /* - * Yikes! Tagged queue full comes through this path! - * - * So we'll change it to a status error and anything - * that returns status should probably be a status - * error as well. - */ - xs->resid = xs->datalen - mpt_reply->TransferCount; - if (mpt_reply->SCSIState & - MPI_SCSI_STATE_NO_SCSI_STATUS) { - xs->error = XS_DRIVER_STUFFUP; - break; - } - /* FALLTHROUGH */ - case MPI_IOCSTATUS_SUCCESS: - case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: - switch (xs->status) { - case SCSI_OK: - xs->resid = 0; - break; - - case SCSI_CHECK: - xs->error = XS_SENSE; - break; - - case SCSI_BUSY: - xs->error = XS_BUSY; - break; - - case SCSI_QUEUE_FULL: - xs->error = XS_TIMEOUT; - xs->retries++; - break; - default: - sc_print_addr(linkp); - mpt_prt(mpt, "invalid status code %d", xs->status); - xs->error = XS_DRIVER_STUFFUP; - break; - } - break; - - case MPI_IOCSTATUS_BUSY: - case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: - xs->error = XS_BUSY; - break; - - case MPI_IOCSTATUS_SCSI_INVALID_BUS: - case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: - case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: - xs->error = XS_SELTIMEOUT; - break; - - case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: - xs->error = XS_DRIVER_STUFFUP; - break; - - case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: - xs->error = XS_DRIVER_STUFFUP; - break; - - case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: - /* XXX */ - xs->error = XS_DRIVER_STUFFUP; - break; - - case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: - /* XXX */ - xs->error = XS_DRIVER_STUFFUP; - break; - - case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: - /* XXX This is a bus-reset */ - xs->error = XS_DRIVER_STUFFUP; - break; - - default: - /* XXX unrecognized HBA error */ - xs->error = XS_DRIVER_STUFFUP; - break; - } - - if (mpt_reply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) { - memcpy(&xs->sense, req->sense_vbuf, - sizeof(xs->sense)); - } else if (mpt_reply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) { - /* - * This will cause the scsi layer to issue - * a REQUEST SENSE. - */ - if (xs->status == SCSI_CHECK) - xs->error = XS_BUSY; - } - - done: - /* If IOC done with this requeset, free it up. */ - if (mpt_reply == NULL || (mpt_reply->MsgFlags & 0x80) == 0) - mpt_free_request(mpt, req); - - /* If address reply, give the buffer back to the IOC. */ - if (mpt_reply != NULL) - mpt_free_reply(mpt, (reply << 1)); - - if (xs != NULL) { - xs->flags |= ITSDONE; - scsi_done(xs); - } -} - -int -mpt_run_xfer(struct mpt_softc *mpt, struct scsi_xfer *xs) -{ - struct scsi_link *linkp = xs->sc_link; - struct req_entry *req; - MSG_SCSI_IO_REQUEST *mpt_req; - int error, s; - - s = splbio(); - req = mpt_get_request(mpt); - if (req == NULL) { - /* This should happen very infrequently. */ - xs->error = XS_DRIVER_STUFFUP; - xs->flags |= ITSDONE; - scsi_done(xs); - splx(s); - return (COMPLETE); - } - splx(s); - - /* Link the req and the scsi_xfer. */ - req->xfer = xs; - - /* Now we build the command for the IOC */ - mpt_req = req->req_vbuf; - bzero(mpt_req, sizeof(*mpt_req)); - - mpt_req->Function = MPI_FUNCTION_SCSI_IO_REQUEST; - mpt_req->Bus = mpt->bus; - - mpt_req->SenseBufferLength = - (sizeof(xs->sense) < MPT_SENSE_SIZE) ? - sizeof(xs->sense) : MPT_SENSE_SIZE; - - /* - * We use the message context to find the request structure when - * we get the command completion interrupt from the IOC. - */ - mpt_req->MsgContext = req->index; - - /* Which physical device to do the I/O on. */ - mpt_req->TargetID = linkp->target; - mpt_req->LUN[1] = linkp->lun; - - /* Set the direction of the transfer. */ - if (xs->flags & SCSI_DATA_IN) - mpt_req->Control = MPI_SCSIIO_CONTROL_READ; - else if (xs->flags & SCSI_DATA_OUT) - mpt_req->Control = MPI_SCSIIO_CONTROL_WRITE; - else - mpt_req->Control = MPI_SCSIIO_CONTROL_NODATATRANSFER; - - mpt_check_xfer_settings(mpt, xs, mpt_req); - - /* Copy the SCSI command block into place. */ - memcpy(mpt_req->CDB, xs->cmd, xs->cmdlen); - - mpt_req->CDBLength = xs->cmdlen; - mpt_req->DataLength = xs->datalen; - mpt_req->SenseBufferLowAddr = req->sense_pbuf; - - /* - * Map the DMA transfer. - */ - if (xs->datalen) { - SGE_SIMPLE32 *se; - - error = bus_dmamap_load(mpt->sc_dmat, req->dmap, xs->data, - xs->datalen, NULL, - ((xs->flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT - : BUS_DMA_WAITOK) | - BUS_DMA_STREAMING | - ((xs->flags & SCSI_DATA_IN) ? BUS_DMA_READ - : BUS_DMA_WRITE)); - switch (error) { - case 0: - break; - - case ENOMEM: - case EAGAIN: - xs->error = XS_DRIVER_STUFFUP; - goto out_bad; - default: - mpt_prt(mpt, "error %d loading DMA map", error); - out_bad: - s = splbio(); - mpt_free_request(mpt, req); - splx(s); - return (TRY_AGAIN_LATER); - } - - if (req->dmap->dm_nsegs > MPT_NSGL_FIRST(mpt)) { - int seg, i, nleft = req->dmap->dm_nsegs; - uint32_t flags; - SGE_CHAIN32 *ce; - - seg = 0; - - mpt_req->DataLength = xs->datalen; - flags = MPI_SGE_FLAGS_SIMPLE_ELEMENT; - if (xs->flags & SCSI_DATA_OUT) - flags |= MPI_SGE_FLAGS_HOST_TO_IOC; - - se = (SGE_SIMPLE32 *) &mpt_req->SGL; - for (i = 0; i < MPT_NSGL_FIRST(mpt) - 1; - i++, se++, seg++) { - uint32_t tf; - - bzero(se, sizeof(*se)); - se->Address = req->dmap->dm_segs[seg].ds_addr; - MPI_pSGE_SET_LENGTH(se, - req->dmap->dm_segs[seg].ds_len); - tf = flags; - if (i == MPT_NSGL_FIRST(mpt) - 2) - tf |= MPI_SGE_FLAGS_LAST_ELEMENT; - MPI_pSGE_SET_FLAGS(se, tf); - nleft--; - } - - /* - * Tell the IOC where to find the first chain element. - */ - mpt_req->ChainOffset = - ((char *)se - (char *)mpt_req) >> 2; - - /* - * Until we're finished with all segments... - */ - while (nleft) { - int ntodo; - - /* - * Construct the chain element that points to - * the next segment. - */ - ce = (SGE_CHAIN32 *) se++; - if (nleft > MPT_NSGL(mpt)) { - ntodo = MPT_NSGL(mpt) - 1; - ce->NextChainOffset = (MPT_RQSL(mpt) - - sizeof(SGE_SIMPLE32)) >> 2; - ce->Length = MPT_NSGL(mpt) - * sizeof(SGE_SIMPLE32); - } else { - ntodo = nleft; - ce->NextChainOffset = 0; - ce->Length = ntodo - * sizeof(SGE_SIMPLE32); - } - ce->Address = req->req_pbuf + - ((char *)se - (char *)mpt_req); - ce->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT; - for (i = 0; i < ntodo; i++, se++, seg++) { - uint32_t tf; - - bzero(se, sizeof(*se)); - se->Address = - req->dmap->dm_segs[seg].ds_addr; - MPI_pSGE_SET_LENGTH(se, - req->dmap->dm_segs[seg].ds_len); - tf = flags; - if (i == ntodo - 1) { - tf |= - MPI_SGE_FLAGS_LAST_ELEMENT; - if (ce->NextChainOffset == 0) { - tf |= - MPI_SGE_FLAGS_END_OF_LIST | - MPI_SGE_FLAGS_END_OF_BUFFER; - } - } - MPI_pSGE_SET_FLAGS(se, tf); - nleft--; - } - } - bus_dmamap_sync(mpt->sc_dmat, req->dmap, 0, - req->dmap->dm_mapsize, - (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD : - BUS_DMASYNC_PREWRITE); - } else { - int i; - uint32_t flags; - - mpt_req->DataLength = xs->datalen; - flags = MPI_SGE_FLAGS_SIMPLE_ELEMENT; - if (xs->flags & SCSI_DATA_OUT) - flags |= MPI_SGE_FLAGS_HOST_TO_IOC; - - /* Copy the segments into our SG list. */ - se = (SGE_SIMPLE32 *) &mpt_req->SGL; - for (i = 0; i < req->dmap->dm_nsegs; - i++, se++) { - uint32_t tf; - - bzero(se, sizeof(*se)); - se->Address = req->dmap->dm_segs[i].ds_addr; - MPI_pSGE_SET_LENGTH(se, - req->dmap->dm_segs[i].ds_len); - tf = flags; - if (i == req->dmap->dm_nsegs - 1) { - tf |= - MPI_SGE_FLAGS_LAST_ELEMENT | - MPI_SGE_FLAGS_END_OF_BUFFER | - MPI_SGE_FLAGS_END_OF_LIST; - } - MPI_pSGE_SET_FLAGS(se, tf); - } - bus_dmamap_sync(mpt->sc_dmat, req->dmap, 0, - req->dmap->dm_mapsize, - (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD : - BUS_DMASYNC_PREWRITE); - } - } else { - /* - * No data to transfer; just make a single simple SGL - * with zero length. - */ - SGE_SIMPLE32 *se = (SGE_SIMPLE32 *) &mpt_req->SGL; - bzero(se, sizeof(*se)); - MPI_pSGE_SET_FLAGS(se, - (MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | - MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_LIST)); - } - -#ifdef MPT_DEBUG - if (mpt_debug > 50) - mpt_print_scsi_io_request(mpt_req); -#endif /* MPT_DEBUG */ - - s = splbio(); - - /* Always reset xs->stimeout, lest we timeout_del() with trash */ - timeout_set(&xs->stimeout, mpt_timeout, req); - - if ((xs->flags & SCSI_POLL) == 0) - timeout_add(&xs->stimeout, mstohz(xs->timeout)); - mpt_send_cmd(mpt, req); - splx(s); - - if ((xs->flags & SCSI_POLL) == 0) { - return (SUCCESSFULLY_QUEUED); - } - /* - * If we can't use interrupts, poll on completion. - */ - if (mpt_poll(mpt, xs, xs->timeout)) { - mpt_timeout(req); - /* XXX scsi_done called - return (TRY_AGAIN_LATER); - */ - /* XXX MP this does not look correct */ - return (COMPLETE); - } - - return (COMPLETE); -} - -void -mpt_ctlop(struct mpt_softc *mpt, void *vmsg, uint32_t reply) -{ - MSG_DEFAULT_REPLY *dmsg = vmsg; - - switch (dmsg->Function) { - case MPI_FUNCTION_EVENT_NOTIFICATION: - mpt_event_notify_reply(mpt, vmsg); - mpt_free_reply(mpt, (reply << 1)); - break; - - case MPI_FUNCTION_EVENT_ACK: - mpt_free_reply(mpt, (reply << 1)); - break; - - case MPI_FUNCTION_PORT_ENABLE: - { - MSG_PORT_ENABLE_REPLY *msg = vmsg; - int index = msg->MsgContext & ~0x80000000; - - DNPRINTF(10, "%s: enable port reply index %d\n", - DEVNAME(mpt), index); - - if (index >= 0 && index < MPT_MAX_REQUESTS(mpt)) { - struct req_entry *req = &mpt->request_pool[index]; - req->debug = REQ_DONE; - } - mpt_free_reply(mpt, (reply << 1)); - break; - } - - case MPI_FUNCTION_CONFIG: - { - MSG_CONFIG_REPLY *msg = vmsg; - int index = msg->MsgContext & ~0x80000000; - if (index >= 0 && index < MPT_MAX_REQUESTS(mpt)) { - struct req_entry *req = &mpt->request_pool[index]; - req->debug = REQ_DONE; - req->sequence = reply; - } else - mpt_free_reply(mpt, (reply << 1)); - break; - } - - default: - mpt_prt(mpt, "unknown ctlop: 0x%x", dmsg->Function); - } -} - -void -mpt_event_notify_reply(struct mpt_softc *mpt, MSG_EVENT_NOTIFY_REPLY *msg) -{ - - switch (msg->Event) { - case MPI_EVENT_LOG_DATA: - { - int i; - - /* Some error occurrerd that the Fusion wants logged. */ - mpt_prt(mpt, "EvtLogData: IOCLogInfo: 0x%08x", msg->IOCLogInfo); - mpt_prt(mpt, "EvtLogData: Event Data:"); - for (i = 0; i < msg->EventDataLength; i++) { - if ((i % 4) == 0) - printf("%s:\t", mpt->mpt_dev.dv_xname); - printf("0x%08x%c", msg->Data[i], - ((i % 4) == 3) ? '\n' : ' '); - } - if ((i % 4) != 0) - printf("\n"); - break; - } - - case MPI_EVENT_UNIT_ATTENTION: - mpt_prt(mpt, "Unit Attn: Bus 0x%02x Target 0x%02x", - (msg->Data[0] >> 8) & 0xff, msg->Data[0] & 0xff); - break; - - case MPI_EVENT_IOC_BUS_RESET: - /* We generated a bus reset. */ - mpt_prt(mpt, "IOC Bus Reset Port %d", - (msg->Data[0] >> 8) & 0xff); - break; - - case MPI_EVENT_EXT_BUS_RESET: - /* Someone else generated a bus reset. */ - mpt_prt(mpt, "External Bus Reset"); - /* - * These replies don't return EventData like the MPI - * spec says they do. - */ - /* XXX Send an async event? */ - break; - - case MPI_EVENT_RESCAN: - /* - * In general, thise means a device has been added - * to the loop. - */ - mpt_prt(mpt, "Rescan Port %d", (msg->Data[0] >> 8) & 0xff); - /* XXX Send an async event? */ - break; - - case MPI_EVENT_LINK_STATUS_CHANGE: - mpt_prt(mpt, "Port %d: Link state %s", - (msg->Data[1] >> 8) & 0xff, - (msg->Data[0] & 0xff) == 0 ? "Failed" : "Active"); - break; - - case MPI_EVENT_LOOP_STATE_CHANGE: - switch ((msg->Data[0] >> 16) & 0xff) { - case 0x01: - mpt_prt(mpt, - "Port %d: FC Link Event: LIP(%02x,%02x) " - "(Loop Initialization)", - (msg->Data[1] >> 8) & 0xff, - (msg->Data[0] >> 8) & 0xff, - (msg->Data[0] ) & 0xff); - switch ((msg->Data[0] >> 8) & 0xff) { - case 0xf7: - if ((msg->Data[0] & 0xff) == 0xf7) - mpt_prt(mpt, "\tDevice needs AL_PA"); - else - mpt_prt(mpt, "\tDevice %02x doesn't " - "like FC performance", - msg->Data[0] & 0xff); - break; - - case 0xf8: - if ((msg->Data[0] & 0xff) == 0xf7) - mpt_prt(mpt, "\tDevice detected loop " - "failure before acquiring AL_PA"); - else - mpt_prt(mpt, "\tDevice %02x detected " - "loop failure", - msg->Data[0] & 0xff); - break; - - default: - mpt_prt(mpt, "\tDevice %02x requests that " - "device %02x reset itself", - msg->Data[0] & 0xff, - (msg->Data[0] >> 8) & 0xff); - break; - } - break; - - case 0x02: - mpt_prt(mpt, "Port %d: FC Link Event: LPE(%02x,%02x) " - "(Loop Port Enable)", - (msg->Data[1] >> 8) & 0xff, - (msg->Data[0] >> 8) & 0xff, - (msg->Data[0] ) & 0xff); - break; - - case 0x03: - mpt_prt(mpt, "Port %d: FC Link Event: LPB(%02x,%02x) " - "(Loop Port Bypass)", - (msg->Data[1] >> 8) & 0xff, - (msg->Data[0] >> 8) & 0xff, - (msg->Data[0] ) & 0xff); - break; - - default: - mpt_prt(mpt, "Port %d: FC Link Event: " - "Unknown event (%02x %02x %02x)", - (msg->Data[1] >> 8) & 0xff, - (msg->Data[0] >> 16) & 0xff, - (msg->Data[0] >> 8) & 0xff, - (msg->Data[0] ) & 0xff); - break; - } - break; - - case MPI_EVENT_LOGOUT: - mpt_prt(mpt, "Port %d: FC Logout: N_PortID: %02x", - (msg->Data[1] >> 8) & 0xff, msg->Data[0]); - break; - - case MPI_EVENT_EVENT_CHANGE: - /* - * This is just an acknowledgement of our - * mpt_send_event_request(). - */ - break; - - default: - mpt_prt(mpt, "Unknown async event: 0x%x", msg->Event); - break; - } - - if (msg->AckRequired) { - MSG_EVENT_ACK *ackp; - struct req_entry *req; - - if ((req = mpt_get_request(mpt)) == NULL) { - /* XXX XXX XXX XXXJRT */ - panic("mpt_event_notify_reply: unable to allocate " - "request structure"); - } - - ackp = (MSG_EVENT_ACK *) req->req_vbuf; - bzero(ackp, sizeof(*ackp)); - ackp->Function = MPI_FUNCTION_EVENT_ACK; - ackp->Event = msg->Event; - ackp->EventContext = msg->EventContext; - ackp->MsgContext = req->index | 0x80000000; - mpt_check_doorbell(mpt); - mpt_send_cmd(mpt, req); - } -} - -void -mpt_check_xfer_settings(struct mpt_softc *mpt, struct scsi_xfer *xs, MSG_SCSI_IO_REQUEST *mpt_req) -{ - if (mpt->is_fc) { - /* - * SCSI transport settings don't make any sense for - * Fibre Channel; silently ignore the request. - */ - return; - } - - /* - * XXX never do these commands with tags. Should really be - * in a higher layer. - */ - if (xs->cmd->opcode == INQUIRY || - xs->cmd->opcode == TEST_UNIT_READY || - xs->cmd->opcode == REQUEST_SENSE) - return; - - /* Set the queue behavior. */ - if (mpt->is_fc || (mpt->mpt_tag_enable & (1 << xs->sc_link->target))) { - mpt_req->Control |= MPI_SCSIIO_CONTROL_SIMPLEQ; - } else { - mpt_req->Control |= MPI_SCSIIO_CONTROL_UNTAGGED; - mpt_req->Control |= MPI_SCSIIO_CONTROL_NO_DISCONNECT; - } -} - -/***************************************************************************** - * SCSI interface routines - *****************************************************************************/ - -int -mpt_action(struct scsi_xfer *xfer) -{ - struct mpt_softc *mpt = (void *) xfer->sc_link->adapter_softc; - int ret; - - ret = mpt_run_xfer(mpt, xfer); - - return ret; -} - -void -mpt_minphys(struct buf *bp) -{ - -/* - * Subtract one from the SGL limit, since we need an extra one to handle - * an non-page-aligned transfer. - */ -#define MPT_MAX_XFER ((MPT_SGL_MAX - 1) * PAGE_SIZE) - - if (bp->b_bcount > MPT_MAX_XFER) - bp->b_bcount = MPT_MAX_XFER; - minphys(bp); -} - -/* - * Allocate DMA resources for FW image - * - * img_sz : size of image - * maxsgl : maximum number of DMA segments - */ -int -mpt_alloc_fw_mem(struct mpt_softc *mpt, int maxsgl) -{ - int error, rseg; - - error = bus_dmamap_create(mpt->sc_dmat, mpt->fw_image_size, maxsgl, - mpt->fw_image_size, 0, 0, &mpt->fw_dmap); - if (error) { - mpt_prt(mpt, "unable to create request DMA map, error = %d", - error); - return (error); - } - - error = bus_dmamem_alloc(mpt->sc_dmat, mpt->fw_image_size, PAGE_SIZE, 0, - &mpt->fw_seg, 1, &rseg, 0); - if (error) { - mpt_prt(mpt, "unable to allocate fw memory, error = %d", error); - goto destroy; - } - - error = bus_dmamem_map(mpt->sc_dmat, &mpt->fw_seg, 1, - mpt->fw_image_size, (caddr_t *)&mpt->fw, BUS_DMA_COHERENT); - if (error) { - mpt_prt(mpt, "unable to map fw area, error = %d", error); - goto free; - } - - error = bus_dmamap_load(mpt->sc_dmat, mpt->fw_dmap, mpt->fw, - mpt->fw_image_size, NULL, 0); - if (error) { - mpt_prt(mpt, "unable to load request DMA map, error = %d", - error); - goto unmap; - } - - return(error); - -unmap: - bus_dmamem_unmap(mpt->sc_dmat, (caddr_t)mpt->fw, mpt->fw_image_size); -free: - bus_dmamem_free(mpt->sc_dmat, &mpt->fw_seg, 1); -destroy: - bus_dmamap_destroy(mpt->sc_dmat, mpt->fw_dmap); - - mpt->fw = NULL; - bzero(&mpt->fw_seg, sizeof(mpt->fw_seg)); - - return (error); -} - -void -mpt_free_fw_mem(struct mpt_softc *mpt) -{ - bus_dmamap_unload(mpt->sc_dmat, mpt->fw_dmap); - bus_dmamem_unmap(mpt->sc_dmat, (caddr_t)mpt->fw, mpt->fw_image_size); - bus_dmamem_free(mpt->sc_dmat, &mpt->fw_seg, 1); - bus_dmamap_destroy(mpt->sc_dmat, mpt->fw_dmap); -} |