The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ic/mpt_netbsd.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: mpt_netbsd.c,v 1.14.14.1 2010/12/02 23:45:59 snj Exp $ */
    2 
    3 /*
    4  * Copyright (c) 2003 Wasabi Systems, Inc.
    5  * All rights reserved.
    6  *
    7  * Written by Jason R. Thorpe for Wasabi Systems, Inc.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 3. All advertising materials mentioning features or use of this software
   18  *    must display the following acknowledgement:
   19  *      This product includes software developed for the NetBSD Project by
   20  *      Wasabi Systems, Inc.
   21  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
   22  *    or promote products derived from this software without specific prior
   23  *    written permission.
   24  *
   25  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
   26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
   29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   35  * POSSIBILITY OF SUCH DAMAGE.
   36  */
   37 
   38 /*
   39  * Copyright (c) 2000, 2001 by Greg Ansley
   40  * Partially derived from Matt Jacob's ISP driver.
   41  *
   42  * Redistribution and use in source and binary forms, with or without
   43  * modification, are permitted provided that the following conditions
   44  * are met:
   45  * 1. Redistributions of source code must retain the above copyright
   46  *    notice immediately at the beginning of the file, without modification,
   47  *    this list of conditions, and the following disclaimer.
   48  * 2. The name of the author may not be used to endorse or promote products
   49  *    derived from this software without specific prior written permission.
   50  *
   51  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   52  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   53  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   54  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   55  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   56  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   57  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   58  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   59  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   60  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   61  * SUCH DAMAGE.
   62  */
   63 /*
   64  * Additional Copyright (c) 2002 by Matthew Jacob under same license.
   65  */
   66 
   67 /*
   68  * mpt_netbsd.c:
   69  *
   70  * NetBSD-specific routines for LSI Fusion adapters.  Includes some
   71  * bus_dma glue, and SCSIPI glue.
   72  *
   73  * Adapted from the FreeBSD "mpt" driver by Jason R. Thorpe for
   74  * Wasabi Systems, Inc.
   75  *
   76  * Additional contributions by Garrett D'Amore on behalf of TELES AG.
   77  */
   78 
   79 #include <sys/cdefs.h>
   80 __KERNEL_RCSID(0, "$NetBSD: mpt_netbsd.c,v 1.14.14.1 2010/12/02 23:45:59 snj Exp $");
   81 
   82 #include <dev/ic/mpt.h>                 /* pulls in all headers */
   83 
   84 #include <machine/stdarg.h>             /* for mpt_prt() */
   85 
   86 static int      mpt_poll(mpt_softc_t *, struct scsipi_xfer *, int);
   87 static void     mpt_timeout(void *);
   88 static void     mpt_done(mpt_softc_t *, uint32_t);
   89 static void     mpt_run_xfer(mpt_softc_t *, struct scsipi_xfer *);
   90 static void     mpt_set_xfer_mode(mpt_softc_t *, struct scsipi_xfer_mode *);
   91 static void     mpt_get_xfer_mode(mpt_softc_t *, struct scsipi_periph *);
   92 static void     mpt_ctlop(mpt_softc_t *, void *vmsg, uint32_t);
   93 static void     mpt_event_notify_reply(mpt_softc_t *, MSG_EVENT_NOTIFY_REPLY *);
   94 
   95 static void     mpt_scsipi_request(struct scsipi_channel *,
   96                     scsipi_adapter_req_t, void *);
   97 static void     mpt_minphys(struct buf *);
   98 
   99 void
  100 mpt_scsipi_attach(mpt_softc_t *mpt)
  101 {
  102         struct scsipi_adapter *adapt = &mpt->sc_adapter;
  103         struct scsipi_channel *chan = &mpt->sc_channel;
  104         int maxq;
  105 
  106         mpt->bus = 0;           /* XXX ?? */
  107 
  108         maxq = (mpt->mpt_global_credits < MPT_MAX_REQUESTS(mpt)) ?
  109             mpt->mpt_global_credits : MPT_MAX_REQUESTS(mpt);
  110 
  111         /* Fill in the scsipi_adapter. */
  112         memset(adapt, 0, sizeof(*adapt));
  113         adapt->adapt_dev = &mpt->sc_dev;
  114         adapt->adapt_nchannels = 1;
  115         adapt->adapt_openings = maxq;
  116         adapt->adapt_max_periph = maxq;
  117         adapt->adapt_request = mpt_scsipi_request;
  118         adapt->adapt_minphys = mpt_minphys;
  119 
  120         /* Fill in the scsipi_channel. */
  121         memset(chan, 0, sizeof(*chan));
  122         chan->chan_adapter = adapt;
  123         chan->chan_bustype = &scsi_bustype;
  124         chan->chan_channel = 0;
  125         chan->chan_flags = 0;
  126         chan->chan_nluns = 8;
  127         chan->chan_ntargets = mpt->mpt_max_devices;
  128         chan->chan_id = mpt->mpt_ini_id;
  129 
  130         (void) config_found(&mpt->sc_dev, &mpt->sc_channel, scsiprint);
  131 }
  132 
  133 int
  134 mpt_dma_mem_alloc(mpt_softc_t *mpt)
  135 {
  136         bus_dma_segment_t reply_seg, request_seg;
  137         int reply_rseg, request_rseg;
  138         bus_addr_t pptr, end;
  139         char *vptr;
  140         size_t len;
  141         int error, i;
  142 
  143         /* Check if we have already allocated the reply memory. */
  144         if (mpt->reply != NULL)
  145                 return (0);
  146 
  147         /*
  148          * Allocate the request pool.  This isn't really DMA'd memory,
  149          * but it's a convenient place to do it.
  150          */
  151         len = sizeof(request_t) * MPT_MAX_REQUESTS(mpt);
  152         mpt->request_pool = malloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
  153         if (mpt->request_pool == NULL) {
  154                 aprint_error_dev(&mpt->sc_dev, "unable to allocate request pool\n");
  155                 return (ENOMEM);
  156         }
  157 
  158         /*
  159          * Allocate DMA resources for reply buffers.
  160          */
  161         error = bus_dmamem_alloc(mpt->sc_dmat, PAGE_SIZE, PAGE_SIZE, 0,
  162             &reply_seg, 1, &reply_rseg, 0);
  163         if (error) {
  164                 aprint_error_dev(&mpt->sc_dev, "unable to allocate reply area, error = %d\n",
  165                     error);
  166                 goto fail_0;
  167         }
  168 
  169         error = bus_dmamem_map(mpt->sc_dmat, &reply_seg, reply_rseg, PAGE_SIZE,
  170             (void **) &mpt->reply, BUS_DMA_COHERENT/*XXX*/);
  171         if (error) {
  172                 aprint_error_dev(&mpt->sc_dev, "unable to map reply area, error = %d\n",
  173                     error);
  174                 goto fail_1;
  175         }
  176 
  177         error = bus_dmamap_create(mpt->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE,
  178             0, 0, &mpt->reply_dmap);
  179         if (error) {
  180                 aprint_error_dev(&mpt->sc_dev, "unable to create reply DMA map, error = %d\n",
  181                     error);
  182                 goto fail_2;
  183         }
  184 
  185         error = bus_dmamap_load(mpt->sc_dmat, mpt->reply_dmap, mpt->reply,
  186             PAGE_SIZE, NULL, 0);
  187         if (error) {
  188                 aprint_error_dev(&mpt->sc_dev, "unable to load reply DMA map, error = %d\n",
  189                     error);
  190                 goto fail_3;
  191         }
  192         mpt->reply_phys = mpt->reply_dmap->dm_segs[0].ds_addr;
  193 
  194         /*
  195          * Allocate DMA resources for request buffers.
  196          */
  197         error = bus_dmamem_alloc(mpt->sc_dmat, MPT_REQ_MEM_SIZE(mpt),
  198             PAGE_SIZE, 0, &request_seg, 1, &request_rseg, 0);
  199         if (error) {
  200                 aprint_error_dev(&mpt->sc_dev, "unable to allocate request area, "
  201                     "error = %d\n", error);
  202                 goto fail_4;
  203         }
  204 
  205         error = bus_dmamem_map(mpt->sc_dmat, &request_seg, request_rseg,
  206             MPT_REQ_MEM_SIZE(mpt), (void **) &mpt->request, 0);
  207         if (error) {
  208                 aprint_error_dev(&mpt->sc_dev, "unable to map request area, error = %d\n",
  209                     error);
  210                 goto fail_5;
  211         }
  212 
  213         error = bus_dmamap_create(mpt->sc_dmat, MPT_REQ_MEM_SIZE(mpt), 1,
  214             MPT_REQ_MEM_SIZE(mpt), 0, 0, &mpt->request_dmap);
  215         if (error) {
  216                 aprint_error_dev(&mpt->sc_dev, "unable to create request DMA map, "
  217                     "error = %d\n", error);
  218                 goto fail_6;
  219         }
  220 
  221         error = bus_dmamap_load(mpt->sc_dmat, mpt->request_dmap, mpt->request,
  222             MPT_REQ_MEM_SIZE(mpt), NULL, 0);
  223         if (error) {
  224                 aprint_error_dev(&mpt->sc_dev, "unable to load request DMA map, error = %d\n",
  225                     error);
  226                 goto fail_7;
  227         }
  228         mpt->request_phys = mpt->request_dmap->dm_segs[0].ds_addr;
  229 
  230         pptr = mpt->request_phys;
  231         vptr = (void *) mpt->request;
  232         end = pptr + MPT_REQ_MEM_SIZE(mpt);
  233 
  234         for (i = 0; pptr < end; i++) {
  235                 request_t *req = &mpt->request_pool[i];
  236                 req->index = i;
  237 
  238                 /* Store location of Request Data */
  239                 req->req_pbuf = pptr;
  240                 req->req_vbuf = vptr;
  241 
  242                 pptr += MPT_REQUEST_AREA;
  243                 vptr += MPT_REQUEST_AREA;
  244 
  245                 req->sense_pbuf = (pptr - MPT_SENSE_SIZE);
  246                 req->sense_vbuf = (vptr - MPT_SENSE_SIZE);
  247 
  248                 error = bus_dmamap_create(mpt->sc_dmat, MAXPHYS,
  249                     MPT_SGL_MAX, MAXPHYS, 0, 0, &req->dmap);
  250                 if (error) {
  251                         aprint_error_dev(&mpt->sc_dev, "unable to create req %d DMA map, "
  252                             "error = %d\n", i, error);
  253                         goto fail_8;
  254                 }
  255         }
  256 
  257         return (0);
  258 
  259  fail_8:
  260         for (--i; i >= 0; i--) {
  261                 request_t *req = &mpt->request_pool[i];
  262                 if (req->dmap != NULL)
  263                         bus_dmamap_destroy(mpt->sc_dmat, req->dmap);
  264         }
  265         bus_dmamap_unload(mpt->sc_dmat, mpt->request_dmap);
  266  fail_7:
  267         bus_dmamap_destroy(mpt->sc_dmat, mpt->request_dmap);
  268  fail_6:
  269         bus_dmamem_unmap(mpt->sc_dmat, (void *)mpt->request, PAGE_SIZE);
  270  fail_5:
  271         bus_dmamem_free(mpt->sc_dmat, &request_seg, request_rseg);
  272  fail_4:
  273         bus_dmamap_unload(mpt->sc_dmat, mpt->reply_dmap);
  274  fail_3:
  275         bus_dmamap_destroy(mpt->sc_dmat, mpt->reply_dmap);
  276  fail_2:
  277         bus_dmamem_unmap(mpt->sc_dmat, (void *)mpt->reply, PAGE_SIZE);
  278  fail_1:
  279         bus_dmamem_free(mpt->sc_dmat, &reply_seg, reply_rseg);
  280  fail_0:
  281         free(mpt->request_pool, M_DEVBUF);
  282 
  283         mpt->reply = NULL;
  284         mpt->request = NULL;
  285         mpt->request_pool = NULL;
  286 
  287         return (error);
  288 }
  289 
  290 int
  291 mpt_intr(void *arg)
  292 {
  293         mpt_softc_t *mpt = arg;
  294         int nrepl = 0;
  295         uint32_t reply;
  296 
  297         if ((mpt_read(mpt, MPT_OFFSET_INTR_STATUS) & MPT_INTR_REPLY_READY) == 0)
  298                 return (0);
  299 
  300         reply = mpt_pop_reply_queue(mpt);
  301         while (reply != MPT_REPLY_EMPTY) {
  302                 nrepl++;
  303                 if (mpt->verbose > 1) {
  304                         if ((reply & MPT_CONTEXT_REPLY) != 0) {
  305                                 /* Address reply; IOC has something to say */
  306                                 mpt_print_reply(MPT_REPLY_PTOV(mpt, reply));
  307                         } else {
  308                                 /* Context reply; all went well */
  309                                 mpt_prt(mpt, "context %u reply OK", reply);
  310                         }
  311                 }
  312                 mpt_done(mpt, reply);
  313                 reply = mpt_pop_reply_queue(mpt);
  314         }
  315         return (nrepl != 0);
  316 }
  317 
  318 void
  319 mpt_prt(mpt_softc_t *mpt, const char *fmt, ...)
  320 {
  321         va_list ap;
  322 
  323         printf("%s: ", device_xname(&mpt->sc_dev));
  324         va_start(ap, fmt);
  325         vprintf(fmt, ap);
  326         va_end(ap);
  327         printf("\n");
  328 }
  329 
  330 static int
  331 mpt_poll(mpt_softc_t *mpt, struct scsipi_xfer *xs, int count)
  332 {
  333 
  334         /* Timeouts are in msec, so we loop in 1000usec cycles */
  335         while (count) {
  336                 mpt_intr(mpt);
  337                 if (xs->xs_status & XS_STS_DONE)
  338                         return (0);
  339                 delay(1000);            /* only happens in boot, so ok */
  340                 count--;
  341         }
  342         return (1);
  343 }
  344 
  345 static void
  346 mpt_timeout(void *arg)
  347 {
  348         request_t *req = arg;
  349         struct scsipi_xfer *xs = req->xfer;
  350         struct scsipi_periph *periph = xs->xs_periph;
  351         mpt_softc_t *mpt =
  352             (void *) periph->periph_channel->chan_adapter->adapt_dev;
  353         uint32_t oseq;
  354         int s;
  355 
  356         scsipi_printaddr(periph);
  357         printf("command timeout\n");
  358 
  359         s = splbio();
  360 
  361         oseq = req->sequence;
  362         mpt->timeouts++;
  363         if (mpt_intr(mpt)) {
  364                 if (req->sequence != oseq) {
  365                         mpt_prt(mpt, "recovered from command timeout");
  366                         splx(s);
  367                         return;
  368                 }
  369         }
  370         mpt_prt(mpt,
  371             "timeout on request index = 0x%x, seq = 0x%08x",
  372             req->index, req->sequence);
  373         mpt_check_doorbell(mpt);
  374         mpt_prt(mpt, "Status 0x%08x, Mask 0x%08x, Doorbell 0x%08x",
  375             mpt_read(mpt, MPT_OFFSET_INTR_STATUS),
  376             mpt_read(mpt, MPT_OFFSET_INTR_MASK),
  377             mpt_read(mpt, MPT_OFFSET_DOORBELL));
  378         mpt_prt(mpt, "request state: %s", mpt_req_state(req->debug));
  379         if (mpt->verbose > 1)
  380                 mpt_print_scsi_io_request((MSG_SCSI_IO_REQUEST *)req->req_vbuf);
  381 
  382         /* XXX WHAT IF THE IOC IS STILL USING IT?? */
  383         req->xfer = NULL;
  384         mpt_free_request(mpt, req);
  385 
  386         xs->error = XS_TIMEOUT;
  387         scsipi_done(xs);
  388 
  389         splx(s);
  390 }
  391 
  392 static void
  393 mpt_done(mpt_softc_t *mpt, uint32_t reply)
  394 {
  395         struct scsipi_xfer *xs = NULL;
  396         struct scsipi_periph *periph;
  397         int index;
  398         request_t *req;
  399         MSG_REQUEST_HEADER *mpt_req;
  400         MSG_SCSI_IO_REPLY *mpt_reply;
  401 
  402         if (__predict_true((reply & MPT_CONTEXT_REPLY) == 0)) {
  403                 /* context reply (ok) */
  404                 mpt_reply = NULL;
  405                 index = reply & MPT_CONTEXT_MASK;
  406         } else {
  407                 /* address reply (error) */
  408 
  409                 /* XXX BUS_DMASYNC_POSTREAD XXX */
  410                 mpt_reply = MPT_REPLY_PTOV(mpt, reply);
  411                 if (mpt->verbose > 1) {
  412                         uint32_t *pReply = (uint32_t *) mpt_reply;
  413 
  414                         mpt_prt(mpt, "Address Reply (index %u):",
  415                             le32toh(mpt_reply->MsgContext) & 0xffff);
  416                         mpt_prt(mpt, "%08x %08x %08x %08x",
  417                             pReply[0], pReply[1], pReply[2], pReply[3]);
  418                         mpt_prt(mpt, "%08x %08x %08x %08x",
  419                             pReply[4], pReply[5], pReply[6], pReply[7]);
  420                         mpt_prt(mpt, "%08x %08x %08x %08x",
  421                             pReply[8], pReply[9], pReply[10], pReply[11]);
  422                 }
  423                 index = le32toh(mpt_reply->MsgContext);
  424         }
  425 
  426         /*
  427          * Address reply with MessageContext high bit set.
  428          * This is most likely a notify message, so we try
  429          * to process it, then free it.
  430          */
  431         if (__predict_false((index & 0x80000000) != 0)) {
  432                 if (mpt_reply != NULL)
  433                         mpt_ctlop(mpt, mpt_reply, reply);
  434                 else
  435                         mpt_prt(mpt, "mpt_done: index 0x%x, NULL reply", index);
  436                 return;
  437         }
  438 
  439         /* Did we end up with a valid index into the table? */
  440         if (__predict_false(index < 0 || index >= MPT_MAX_REQUESTS(mpt))) {
  441                 mpt_prt(mpt, "mpt_done: invalid index (0x%x) in reply", index);
  442                 return;
  443         }
  444 
  445         req = &mpt->request_pool[index];
  446 
  447         /* Make sure memory hasn't been trashed. */
  448         if (__predict_false(req->index != index)) {
  449                 mpt_prt(mpt, "mpt_done: corrupted request_t (0x%x)", index);
  450                 return;
  451         }
  452 
  453         MPT_SYNC_REQ(mpt, req, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
  454         mpt_req = req->req_vbuf;
  455 
  456         /* Short cut for task management replies; nothing more for us to do. */
  457         if (__predict_false(mpt_req->Function == MPI_FUNCTION_SCSI_TASK_MGMT)) {
  458                 if (mpt->verbose > 1)
  459                         mpt_prt(mpt, "mpt_done: TASK MGMT");
  460                 goto done;
  461         }
  462 
  463         if (__predict_false(mpt_req->Function == MPI_FUNCTION_PORT_ENABLE))
  464                 goto done;
  465 
  466         /*
  467          * At this point, it had better be a SCSI I/O command, but don't
  468          * crash if it isn't.
  469          */
  470         if (__predict_false(mpt_req->Function !=
  471                             MPI_FUNCTION_SCSI_IO_REQUEST)) {
  472                 if (mpt->verbose > 1)
  473                         mpt_prt(mpt, "mpt_done: unknown Function 0x%x (0x%x)",
  474                             mpt_req->Function, index);
  475                 goto done;
  476         }
  477 
  478         /* Recover scsipi_xfer from the request structure. */
  479         xs = req->xfer;
  480 
  481         /* Can't have a SCSI command without a scsipi_xfer. */
  482         if (__predict_false(xs == NULL)) {
  483                 mpt_prt(mpt,
  484                     "mpt_done: no scsipi_xfer, index = 0x%x, seq = 0x%08x",
  485                     req->index, req->sequence);
  486                 mpt_prt(mpt, "request state: %s", mpt_req_state(req->debug));
  487                 mpt_prt(mpt, "mpt_request:");
  488                 mpt_print_scsi_io_request((MSG_SCSI_IO_REQUEST *)req->req_vbuf);
  489 
  490                 if (mpt_reply != NULL) {
  491                         mpt_prt(mpt, "mpt_reply:");
  492                         mpt_print_reply(mpt_reply);
  493                 } else {
  494                         mpt_prt(mpt, "context reply: 0x%08x", reply);
  495                 }
  496                 goto done;
  497         }
  498 
  499         callout_stop(&xs->xs_callout);
  500 
  501         periph = xs->xs_periph;
  502 
  503         /*
  504          * If we were a data transfer, unload the map that described
  505          * the data buffer.
  506          */
  507         if (__predict_true(xs->datalen != 0)) {
  508                 bus_dmamap_sync(mpt->sc_dmat, req->dmap, 0,
  509                     req->dmap->dm_mapsize,
  510                     (xs->xs_control & XS_CTL_DATA_IN) ? BUS_DMASYNC_POSTREAD
  511                                                       : BUS_DMASYNC_POSTWRITE);
  512                 bus_dmamap_unload(mpt->sc_dmat, req->dmap);
  513         }
  514 
  515         if (__predict_true(mpt_reply == NULL)) {
  516                 /*
  517                  * Context reply; report that the command was
  518                  * successful!
  519                  *
  520                  * Also report the xfer mode, if necessary.
  521                  */
  522                 if (__predict_false(mpt->mpt_report_xfer_mode != 0)) {
  523                         if ((mpt->mpt_report_xfer_mode &
  524                              (1 << periph->periph_target)) != 0)
  525                                 mpt_get_xfer_mode(mpt, periph);
  526                 }
  527                 xs->error = XS_NOERROR;
  528                 xs->status = SCSI_OK;
  529                 xs->resid = 0;
  530                 mpt_free_request(mpt, req);
  531                 scsipi_done(xs);
  532                 return;
  533         }
  534 
  535         xs->status = mpt_reply->SCSIStatus;
  536         switch (le16toh(mpt_reply->IOCStatus)) {
  537         case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:
  538                 xs->error = XS_DRIVER_STUFFUP;
  539                 break;
  540 
  541         case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:
  542                 /*
  543                  * Yikes!  Tagged queue full comes through this path!
  544                  *
  545                  * So we'll change it to a status error and anything
  546                  * that returns status should probably be a status
  547                  * error as well.
  548                  */
  549                 xs->resid = xs->datalen - le32toh(mpt_reply->TransferCount);
  550                 if (mpt_reply->SCSIState &
  551                     MPI_SCSI_STATE_NO_SCSI_STATUS) {
  552                         xs->error = XS_DRIVER_STUFFUP;
  553                         break;
  554                 }
  555                 /* FALLTHROUGH */
  556         case MPI_IOCSTATUS_SUCCESS:
  557         case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:
  558                 switch (xs->status) {
  559                 case SCSI_OK:
  560                         /* Report the xfer mode, if necessary. */
  561                         if ((mpt->mpt_report_xfer_mode &
  562                              (1 << periph->periph_target)) != 0)
  563                                 mpt_get_xfer_mode(mpt, periph);
  564                         xs->resid = 0;
  565                         break;
  566 
  567                 case SCSI_CHECK:
  568                         xs->error = XS_SENSE;
  569                         break;
  570 
  571                 case SCSI_BUSY:
  572                 case SCSI_QUEUE_FULL:
  573                         xs->error = XS_BUSY;
  574                         break;
  575 
  576                 default:
  577                         scsipi_printaddr(periph);
  578                         printf("invalid status code %d\n", xs->status);
  579                         xs->error = XS_DRIVER_STUFFUP;
  580                         break;
  581                 }
  582                 break;
  583 
  584         case MPI_IOCSTATUS_BUSY:
  585         case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:
  586                 xs->error = XS_RESOURCE_SHORTAGE;
  587                 break;
  588 
  589         case MPI_IOCSTATUS_SCSI_INVALID_BUS:
  590         case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:
  591         case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
  592                 xs->error = XS_SELTIMEOUT;
  593                 break;
  594 
  595         case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
  596                 xs->error = XS_DRIVER_STUFFUP;
  597                 break;
  598 
  599         case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:
  600                 /* XXX What should we do here? */
  601                 break;
  602 
  603         case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
  604                 /* XXX */
  605                 xs->error = XS_DRIVER_STUFFUP;
  606                 break;
  607 
  608         case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:
  609                 /* XXX */
  610                 xs->error = XS_DRIVER_STUFFUP;
  611                 break;
  612 
  613         case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:
  614                 /* XXX This is a bus-reset */
  615                 xs->error = XS_DRIVER_STUFFUP;
  616                 break;
  617 
  618         default:
  619                 /* XXX unrecognized HBA error */
  620                 xs->error = XS_DRIVER_STUFFUP;
  621                 break;
  622         }
  623 
  624         if (mpt_reply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
  625                 memcpy(&xs->sense.scsi_sense, req->sense_vbuf,
  626                     sizeof(xs->sense.scsi_sense));
  627         } else if (mpt_reply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
  628                 /*
  629                  * This will cause the scsipi layer to issue
  630                  * a REQUEST SENSE.
  631                  */
  632                 if (xs->status == SCSI_CHECK)
  633                         xs->error = XS_BUSY;
  634         }
  635 
  636  done:
  637         /* If IOC done with this requeset, free it up. */
  638         if (mpt_reply == NULL || (mpt_reply->MsgFlags & 0x80) == 0)
  639                 mpt_free_request(mpt, req);
  640 
  641         /* If address reply, give the buffer back to the IOC. */
  642         if (mpt_reply != NULL)
  643                 mpt_free_reply(mpt, (reply << 1));
  644 
  645         if (xs != NULL)
  646                 scsipi_done(xs);
  647 }
  648 
  649 static void
  650 mpt_run_xfer(mpt_softc_t *mpt, struct scsipi_xfer *xs)
  651 {
  652         struct scsipi_periph *periph = xs->xs_periph;
  653         request_t *req;
  654         MSG_SCSI_IO_REQUEST *mpt_req;
  655         int error, s;
  656 
  657         s = splbio();
  658         req = mpt_get_request(mpt);
  659         if (__predict_false(req == NULL)) {
  660                 /* This should happen very infrequently. */
  661                 xs->error = XS_RESOURCE_SHORTAGE;
  662                 scsipi_done(xs);
  663                 splx(s);
  664                 return;
  665         }
  666         splx(s);
  667 
  668         /* Link the req and the scsipi_xfer. */
  669         req->xfer = xs;
  670 
  671         /* Now we build the command for the IOC */
  672         mpt_req = req->req_vbuf;
  673         memset(mpt_req, 0, sizeof(*mpt_req));
  674 
  675         mpt_req->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
  676         mpt_req->Bus = mpt->bus;
  677 
  678         mpt_req->SenseBufferLength =
  679             (sizeof(xs->sense.scsi_sense) < MPT_SENSE_SIZE) ?
  680             sizeof(xs->sense.scsi_sense) : MPT_SENSE_SIZE;
  681 
  682         /*
  683          * We use the message context to find the request structure when
  684          * we get the command completion interrupt from the IOC.
  685          */
  686         mpt_req->MsgContext = htole32(req->index);
  687 
  688         /* Which physical device to do the I/O on. */
  689         mpt_req->TargetID = periph->periph_target;
  690         mpt_req->LUN[1] = periph->periph_lun;
  691 
  692         /* Set the direction of the transfer. */
  693         if (xs->xs_control & XS_CTL_DATA_IN)
  694                 mpt_req->Control = MPI_SCSIIO_CONTROL_READ;
  695         else if (xs->xs_control & XS_CTL_DATA_OUT)
  696                 mpt_req->Control = MPI_SCSIIO_CONTROL_WRITE;
  697         else
  698                 mpt_req->Control = MPI_SCSIIO_CONTROL_NODATATRANSFER;
  699 
  700         /* Set the queue behavior. */
  701         if (__predict_true((!mpt->is_scsi) ||
  702                            (mpt->mpt_tag_enable &
  703                             (1 << periph->periph_target)))) {
  704                 switch (XS_CTL_TAGTYPE(xs)) {
  705                 case XS_CTL_HEAD_TAG:
  706                         mpt_req->Control |= MPI_SCSIIO_CONTROL_HEADOFQ;
  707                         break;
  708 
  709 #if 0   /* XXX */
  710                 case XS_CTL_ACA_TAG:
  711                         mpt_req->Control |= MPI_SCSIIO_CONTROL_ACAQ;
  712                         break;
  713 #endif
  714 
  715                 case XS_CTL_ORDERED_TAG:
  716                         mpt_req->Control |= MPI_SCSIIO_CONTROL_ORDEREDQ;
  717                         break;
  718 
  719                 case XS_CTL_SIMPLE_TAG:
  720                         mpt_req->Control |= MPI_SCSIIO_CONTROL_SIMPLEQ;
  721                         break;
  722 
  723                 default:
  724                         if (mpt->is_scsi)
  725                                 mpt_req->Control |= MPI_SCSIIO_CONTROL_UNTAGGED;
  726                         else
  727                                 mpt_req->Control |= MPI_SCSIIO_CONTROL_SIMPLEQ;
  728                         break;
  729                 }
  730         } else
  731                 mpt_req->Control |= MPI_SCSIIO_CONTROL_UNTAGGED;
  732 
  733         if (__predict_false(mpt->is_scsi &&
  734                             (mpt->mpt_disc_enable &
  735                              (1 << periph->periph_target)) == 0))
  736                 mpt_req->Control |= MPI_SCSIIO_CONTROL_NO_DISCONNECT;
  737 
  738         mpt_req->Control = htole32(mpt_req->Control);
  739 
  740         /* Copy the SCSI command block into place. */
  741         memcpy(mpt_req->CDB, xs->cmd, xs->cmdlen);
  742 
  743         mpt_req->CDBLength = xs->cmdlen;
  744         mpt_req->DataLength = htole32(xs->datalen);
  745         mpt_req->SenseBufferLowAddr = htole32(req->sense_pbuf);
  746 
  747         /*
  748          * Map the DMA transfer.
  749          */
  750         if (xs->datalen) {
  751                 SGE_SIMPLE32 *se;
  752 
  753                 error = bus_dmamap_load(mpt->sc_dmat, req->dmap, xs->data,
  754                     xs->datalen, NULL,
  755                     ((xs->xs_control & XS_CTL_NOSLEEP) ? BUS_DMA_NOWAIT
  756                                                        : BUS_DMA_WAITOK) |
  757                     BUS_DMA_STREAMING |
  758                     ((xs->xs_control & XS_CTL_DATA_IN) ? BUS_DMA_READ
  759                                                        : BUS_DMA_WRITE));
  760                 switch (error) {
  761                 case 0:
  762                         break;
  763 
  764                 case ENOMEM:
  765                 case EAGAIN:
  766                         xs->error = XS_RESOURCE_SHORTAGE;
  767                         goto out_bad;
  768 
  769                 default:
  770                         xs->error = XS_DRIVER_STUFFUP;
  771                         mpt_prt(mpt, "error %d loading DMA map", error);
  772  out_bad:
  773                         s = splbio();
  774                         mpt_free_request(mpt, req);
  775                         scsipi_done(xs);
  776                         splx(s);
  777                         return;
  778                 }
  779 
  780                 if (req->dmap->dm_nsegs > MPT_NSGL_FIRST(mpt)) {
  781                         int seg, i, nleft = req->dmap->dm_nsegs;
  782                         uint32_t flags;
  783                         SGE_CHAIN32 *ce;
  784 
  785                         seg = 0;
  786                         flags = MPI_SGE_FLAGS_SIMPLE_ELEMENT;
  787                         if (xs->xs_control & XS_CTL_DATA_OUT)
  788                                 flags |= MPI_SGE_FLAGS_HOST_TO_IOC;
  789 
  790                         se = (SGE_SIMPLE32 *) &mpt_req->SGL;
  791                         for (i = 0; i < MPT_NSGL_FIRST(mpt) - 1;
  792                              i++, se++, seg++) {
  793                                 uint32_t tf;
  794 
  795                                 memset(se, 0, sizeof(*se));
  796                                 se->Address =
  797                                     htole32(req->dmap->dm_segs[seg].ds_addr);
  798                                 MPI_pSGE_SET_LENGTH(se,
  799                                     req->dmap->dm_segs[seg].ds_len);
  800                                 tf = flags;
  801                                 if (i == MPT_NSGL_FIRST(mpt) - 2)
  802                                         tf |= MPI_SGE_FLAGS_LAST_ELEMENT;
  803                                 MPI_pSGE_SET_FLAGS(se, tf);
  804                                 se->FlagsLength = htole32(se->FlagsLength);
  805                                 nleft--;
  806                         }
  807 
  808                         /*
  809                          * Tell the IOC where to find the first chain element.
  810                          */
  811                         mpt_req->ChainOffset =
  812                             ((char *)se - (char *)mpt_req) >> 2;
  813 
  814                         /*
  815                          * Until we're finished with all segments...
  816                          */
  817                         while (nleft) {
  818                                 int ntodo;
  819 
  820                                 /*
  821                                  * Construct the chain element that points to
  822                                  * the next segment.
  823                                  */
  824                                 ce = (SGE_CHAIN32 *) se++;
  825                                 if (nleft > MPT_NSGL(mpt)) {
  826                                         ntodo = MPT_NSGL(mpt) - 1;
  827                                         ce->NextChainOffset = (MPT_RQSL(mpt) -
  828                                             sizeof(SGE_SIMPLE32)) >> 2;
  829                                         ce->Length = htole16(MPT_NSGL(mpt)
  830                                                 * sizeof(SGE_SIMPLE32));
  831                                 } else {
  832                                         ntodo = nleft;
  833                                         ce->NextChainOffset = 0;
  834                                         ce->Length = htole16(ntodo
  835                                                 * sizeof(SGE_SIMPLE32));
  836                                 }
  837                                 ce->Address = htole32(req->req_pbuf +
  838                                     ((char *)se - (char *)mpt_req));
  839                                 ce->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;
  840                                 for (i = 0; i < ntodo; i++, se++, seg++) {
  841                                         uint32_t tf;
  842 
  843                                         memset(se, 0, sizeof(*se));
  844                                         se->Address = htole32(
  845                                             req->dmap->dm_segs[seg].ds_addr);
  846                                         MPI_pSGE_SET_LENGTH(se,
  847                                             req->dmap->dm_segs[seg].ds_len);
  848                                         tf = flags;
  849                                         if (i == ntodo - 1) {
  850                                                 tf |=
  851                                                     MPI_SGE_FLAGS_LAST_ELEMENT;
  852                                                 if (ce->NextChainOffset == 0) {
  853                                                         tf |=
  854                                                     MPI_SGE_FLAGS_END_OF_LIST |
  855                                                     MPI_SGE_FLAGS_END_OF_BUFFER;
  856                                                 }
  857                                         }
  858                                         MPI_pSGE_SET_FLAGS(se, tf);
  859                                         se->FlagsLength =
  860                                             htole32(se->FlagsLength);
  861                                         nleft--;
  862                                 }
  863                         }
  864                         bus_dmamap_sync(mpt->sc_dmat, req->dmap, 0,
  865                             req->dmap->dm_mapsize,
  866                             (xs->xs_control & XS_CTL_DATA_IN) ?
  867                                                         BUS_DMASYNC_PREREAD
  868                                                       : BUS_DMASYNC_PREWRITE);
  869                 } else {
  870                         int i;
  871                         uint32_t flags;
  872 
  873                         flags = MPI_SGE_FLAGS_SIMPLE_ELEMENT;
  874                         if (xs->xs_control & XS_CTL_DATA_OUT)
  875                                 flags |= MPI_SGE_FLAGS_HOST_TO_IOC;
  876 
  877                         /* Copy the segments into our SG list. */
  878                         se = (SGE_SIMPLE32 *) &mpt_req->SGL;
  879                         for (i = 0; i < req->dmap->dm_nsegs;
  880                              i++, se++) {
  881                                 uint32_t tf;
  882 
  883                                 memset(se, 0, sizeof(*se));
  884                                 se->Address =
  885                                     htole32(req->dmap->dm_segs[i].ds_addr);
  886                                 MPI_pSGE_SET_LENGTH(se,
  887                                     req->dmap->dm_segs[i].ds_len);
  888                                 tf = flags;
  889                                 if (i == req->dmap->dm_nsegs - 1) {
  890                                         tf |=
  891                                             MPI_SGE_FLAGS_LAST_ELEMENT |
  892                                             MPI_SGE_FLAGS_END_OF_BUFFER |
  893                                             MPI_SGE_FLAGS_END_OF_LIST;
  894                                 }
  895                                 MPI_pSGE_SET_FLAGS(se, tf);
  896                                 se->FlagsLength = htole32(se->FlagsLength);
  897                         }
  898                         bus_dmamap_sync(mpt->sc_dmat, req->dmap, 0,
  899                             req->dmap->dm_mapsize,
  900                             (xs->xs_control & XS_CTL_DATA_IN) ?
  901                                                         BUS_DMASYNC_PREREAD
  902                                                       : BUS_DMASYNC_PREWRITE);
  903                 }
  904         } else {
  905                 /*
  906                  * No data to transfer; just make a single simple SGL
  907                  * with zero length.
  908                  */
  909                 SGE_SIMPLE32 *se = (SGE_SIMPLE32 *) &mpt_req->SGL;
  910                 memset(se, 0, sizeof(*se));
  911                 MPI_pSGE_SET_FLAGS(se,
  912                     (MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
  913                      MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_LIST));
  914                 se->FlagsLength = htole32(se->FlagsLength);
  915         }
  916 
  917         if (mpt->verbose > 1)
  918                 mpt_print_scsi_io_request(mpt_req);
  919 
  920         s = splbio();
  921         if (__predict_true((xs->xs_control & XS_CTL_POLL) == 0))
  922                 callout_reset(&xs->xs_callout,
  923                     mstohz(xs->timeout), mpt_timeout, req);
  924         mpt_send_cmd(mpt, req);
  925         splx(s);
  926 
  927         if (__predict_true((xs->xs_control & XS_CTL_POLL) == 0))
  928                 return;
  929 
  930         /*
  931          * If we can't use interrupts, poll on completion.
  932          */
  933         if (mpt_poll(mpt, xs, xs->timeout))
  934                 mpt_timeout(req);
  935 }
  936 
  937 static void
  938 mpt_set_xfer_mode(mpt_softc_t *mpt, struct scsipi_xfer_mode *xm)
  939 {
  940         fCONFIG_PAGE_SCSI_DEVICE_1 tmp;
  941 
  942         if (!mpt->is_scsi) {
  943                 /*
  944                  * SCSI transport settings don't make any sense for
  945                  * Fibre Channel; silently ignore the request.
  946                  */
  947                 return;
  948         }
  949 
  950         /*
  951          * Always allow disconnect; we don't have a way to disable
  952          * it right now, in any case.
  953          */
  954         mpt->mpt_disc_enable |= (1 << xm->xm_target);
  955 
  956         if (xm->xm_mode & PERIPH_CAP_TQING)
  957                 mpt->mpt_tag_enable |= (1 << xm->xm_target);
  958         else
  959                 mpt->mpt_tag_enable &= ~(1 << xm->xm_target);
  960 
  961         tmp = mpt->mpt_dev_page1[xm->xm_target];
  962 
  963         /*
  964          * Set the wide/narrow parameter for the target.
  965          */
  966         if (xm->xm_mode & PERIPH_CAP_WIDE16)
  967                 tmp.RequestedParameters |= MPI_SCSIDEVPAGE1_RP_WIDE;
  968         else
  969                 tmp.RequestedParameters &= ~MPI_SCSIDEVPAGE1_RP_WIDE;
  970 
  971         /*
  972          * Set the synchronous parameters for the target.
  973          *
  974          * XXX If we request sync transfers, we just go ahead and
  975          * XXX request the maximum available.  We need finer control
  976          * XXX in order to implement Domain Validation.
  977          */
  978         tmp.RequestedParameters &= ~(MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK |
  979             MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK |
  980             MPI_SCSIDEVPAGE1_RP_DT | MPI_SCSIDEVPAGE1_RP_QAS |
  981             MPI_SCSIDEVPAGE1_RP_IU);
  982         if (xm->xm_mode & PERIPH_CAP_SYNC) {
  983                 int factor, offset, np;
  984 
  985                 factor = (mpt->mpt_port_page0.Capabilities >> 8) & 0xff;
  986                 offset = (mpt->mpt_port_page0.Capabilities >> 16) & 0xff;
  987                 np = 0;
  988                 if (factor < 0x9) {
  989                         /* Ultra320 */
  990                         np |= MPI_SCSIDEVPAGE1_RP_QAS | MPI_SCSIDEVPAGE1_RP_IU;
  991                 }
  992                 if (factor < 0xa) {
  993                         /* at least Ultra160 */
  994                         np |= MPI_SCSIDEVPAGE1_RP_DT;
  995                 }
  996                 np |= (factor << 8) | (offset << 16);
  997                 tmp.RequestedParameters |= np;
  998         }
  999 
 1000         host2mpt_config_page_scsi_device_1(&tmp);
 1001         if (mpt_write_cfg_page(mpt, xm->xm_target, &tmp.Header)) {
 1002                 mpt_prt(mpt, "unable to write Device Page 1");
 1003                 return;
 1004         }
 1005 
 1006         if (mpt_read_cfg_page(mpt, xm->xm_target, &tmp.Header)) {
 1007                 mpt_prt(mpt, "unable to read back Device Page 1");
 1008                 return;
 1009         }
 1010 
 1011         mpt2host_config_page_scsi_device_1(&tmp);
 1012         mpt->mpt_dev_page1[xm->xm_target] = tmp;
 1013         if (mpt->verbose > 1) {
 1014                 mpt_prt(mpt,
 1015                     "SPI Target %d Page 1: RequestedParameters %x Config %x",
 1016                     xm->xm_target,
 1017                     mpt->mpt_dev_page1[xm->xm_target].RequestedParameters,
 1018                     mpt->mpt_dev_page1[xm->xm_target].Configuration);
 1019         }
 1020 
 1021         /*
 1022          * Make a note that we should perform an async callback at the
 1023          * end of the next successful command completion to report the
 1024          * negotiated transfer mode.
 1025          */
 1026         mpt->mpt_report_xfer_mode |= (1 << xm->xm_target);
 1027 }
 1028 
 1029 static void
 1030 mpt_get_xfer_mode(mpt_softc_t *mpt, struct scsipi_periph *periph)
 1031 {
 1032         fCONFIG_PAGE_SCSI_DEVICE_0 tmp;
 1033         struct scsipi_xfer_mode xm;
 1034         int period, offset;
 1035 
 1036         tmp = mpt->mpt_dev_page0[periph->periph_target];
 1037         host2mpt_config_page_scsi_device_0(&tmp);
 1038         if (mpt_read_cfg_page(mpt, periph->periph_target, &tmp.Header)) {
 1039                 mpt_prt(mpt, "unable to read Device Page 0");
 1040                 return;
 1041         }
 1042         mpt2host_config_page_scsi_device_0(&tmp);
 1043 
 1044         if (mpt->verbose > 1) {
 1045                 mpt_prt(mpt,
 1046                     "SPI Tgt %d Page 0: NParms %x Information %x",
 1047                     periph->periph_target,
 1048                     tmp.NegotiatedParameters, tmp.Information);
 1049         }
 1050 
 1051         xm.xm_target = periph->periph_target;
 1052         xm.xm_mode = 0;
 1053 
 1054         if (tmp.NegotiatedParameters & MPI_SCSIDEVPAGE0_NP_WIDE)
 1055                 xm.xm_mode |= PERIPH_CAP_WIDE16;
 1056 
 1057         period = (tmp.NegotiatedParameters >> 8) & 0xff;
 1058         offset = (tmp.NegotiatedParameters >> 16) & 0xff;
 1059         if (offset) {
 1060                 xm.xm_period = period;
 1061                 xm.xm_offset = offset;
 1062                 xm.xm_mode |= PERIPH_CAP_SYNC;
 1063         }
 1064 
 1065         /*
 1066          * Tagged queueing is all controlled by us; there is no
 1067          * other setting to query.
 1068          */
 1069         if (mpt->mpt_tag_enable & (1 << periph->periph_target))
 1070                 xm.xm_mode |= PERIPH_CAP_TQING;
 1071 
 1072         /*
 1073          * We're going to deliver the async event, so clear the marker.
 1074          */
 1075         mpt->mpt_report_xfer_mode &= ~(1 << periph->periph_target);
 1076 
 1077         scsipi_async_event(&mpt->sc_channel, ASYNC_EVENT_XFER_MODE, &xm);
 1078 }
 1079 
 1080 static void
 1081 mpt_ctlop(mpt_softc_t *mpt, void *vmsg, uint32_t reply)
 1082 {
 1083         MSG_DEFAULT_REPLY *dmsg = vmsg;
 1084 
 1085         switch (dmsg->Function) {
 1086         case MPI_FUNCTION_EVENT_NOTIFICATION:
 1087                 mpt_event_notify_reply(mpt, vmsg);
 1088                 mpt_free_reply(mpt, (reply << 1));
 1089                 break;
 1090 
 1091         case MPI_FUNCTION_EVENT_ACK:
 1092                 mpt_free_reply(mpt, (reply << 1));
 1093                 break;
 1094 
 1095         case MPI_FUNCTION_PORT_ENABLE:
 1096             {
 1097                 MSG_PORT_ENABLE_REPLY *msg = vmsg;
 1098                 int index = le32toh(msg->MsgContext) & ~0x80000000;
 1099                 if (mpt->verbose > 1)
 1100                         mpt_prt(mpt, "enable port reply index %d", index);
 1101                 if (index >= 0 && index < MPT_MAX_REQUESTS(mpt)) {
 1102                         request_t *req = &mpt->request_pool[index];
 1103                         req->debug = REQ_DONE;
 1104                 }
 1105                 mpt_free_reply(mpt, (reply << 1));
 1106                 break;
 1107             }
 1108 
 1109         case MPI_FUNCTION_CONFIG:
 1110             {
 1111                 MSG_CONFIG_REPLY *msg = vmsg;
 1112                 int index = le32toh(msg->MsgContext) & ~0x80000000;
 1113                 if (index >= 0 && index < MPT_MAX_REQUESTS(mpt)) {
 1114                         request_t *req = &mpt->request_pool[index];
 1115                         req->debug = REQ_DONE;
 1116                         req->sequence = reply;
 1117                 } else
 1118                         mpt_free_reply(mpt, (reply << 1));
 1119                 break;
 1120             }
 1121 
 1122         default:
 1123                 mpt_prt(mpt, "unknown ctlop: 0x%x", dmsg->Function);
 1124         }
 1125 }
 1126 
 1127 static void
 1128 mpt_event_notify_reply(mpt_softc_t *mpt, MSG_EVENT_NOTIFY_REPLY *msg)
 1129 {
 1130 
 1131         switch (le32toh(msg->Event)) {
 1132         case MPI_EVENT_LOG_DATA:
 1133             {
 1134                 int i;
 1135 
 1136                 /* Some error occurrerd that the Fusion wants logged. */
 1137                 mpt_prt(mpt, "EvtLogData: IOCLogInfo: 0x%08x", msg->IOCLogInfo);
 1138                 mpt_prt(mpt, "EvtLogData: Event Data:");
 1139                 for (i = 0; i < msg->EventDataLength; i++) {
 1140                         if ((i % 4) == 0)
 1141                                 printf("%s:\t", device_xname(&mpt->sc_dev));
 1142                         printf("0x%08x%c", msg->Data[i],
 1143                             ((i % 4) == 3) ? '\n' : ' ');
 1144                 }
 1145                 if ((i % 4) != 0)
 1146                         printf("\n");
 1147                 break;
 1148             }
 1149 
 1150         case MPI_EVENT_UNIT_ATTENTION:
 1151                 mpt_prt(mpt, "Unit Attn: Bus 0x%02x Target 0x%02x",
 1152                     (msg->Data[0] >> 8) & 0xff, msg->Data[0] & 0xff);
 1153                 break;
 1154 
 1155         case MPI_EVENT_IOC_BUS_RESET:
 1156                 /* We generated a bus reset. */
 1157                 mpt_prt(mpt, "IOC Bus Reset Port %d",
 1158                     (msg->Data[0] >> 8) & 0xff);
 1159                 break;
 1160 
 1161         case MPI_EVENT_EXT_BUS_RESET:
 1162                 /* Someone else generated a bus reset. */
 1163                 mpt_prt(mpt, "External Bus Reset");
 1164                 /*
 1165                  * These replies don't return EventData like the MPI
 1166                  * spec says they do.
 1167                  */
 1168                 /* XXX Send an async event? */
 1169                 break;
 1170 
 1171         case MPI_EVENT_RESCAN:
 1172                 /*
 1173                  * In general, thise means a device has been added
 1174                  * to the loop.
 1175                  */
 1176                 mpt_prt(mpt, "Rescan Port %d", (msg->Data[0] >> 8) & 0xff);
 1177                 /* XXX Send an async event? */
 1178                 break;
 1179 
 1180         case MPI_EVENT_LINK_STATUS_CHANGE:
 1181                 mpt_prt(mpt, "Port %d: Link state %s",
 1182                     (msg->Data[1] >> 8) & 0xff,
 1183                     (msg->Data[0] & 0xff) == 0 ? "Failed" : "Active");
 1184                 break;
 1185 
 1186         case MPI_EVENT_LOOP_STATE_CHANGE:
 1187                 switch ((msg->Data[0] >> 16) & 0xff) {
 1188                 case 0x01:
 1189                         mpt_prt(mpt,
 1190                             "Port %d: FC Link Event: LIP(%02x,%02x) "
 1191                             "(Loop Initialization)",
 1192                             (msg->Data[1] >> 8) & 0xff,
 1193                             (msg->Data[0] >> 8) & 0xff,
 1194                             (msg->Data[0]     ) & 0xff);
 1195                         switch ((msg->Data[0] >> 8) & 0xff) {
 1196                         case 0xf7:
 1197                                 if ((msg->Data[0] & 0xff) == 0xf7)
 1198                                         mpt_prt(mpt, "\tDevice needs AL_PA");
 1199                                 else
 1200                                         mpt_prt(mpt, "\tDevice %02x doesn't "
 1201                                             "like FC performance",
 1202                                             msg->Data[0] & 0xff);
 1203                                 break;
 1204 
 1205                         case 0xf8:
 1206                                 if ((msg->Data[0] & 0xff) == 0xf7)
 1207                                         mpt_prt(mpt, "\tDevice detected loop "
 1208                                             "failure before acquiring AL_PA");
 1209                                 else
 1210                                         mpt_prt(mpt, "\tDevice %02x detected "
 1211                                             "loop failure",
 1212                                             msg->Data[0] & 0xff);
 1213                                 break;
 1214 
 1215                         default:
 1216                                 mpt_prt(mpt, "\tDevice %02x requests that "
 1217                                     "device %02x reset itself",
 1218                                     msg->Data[0] & 0xff,
 1219                                     (msg->Data[0] >> 8) & 0xff);
 1220                                 break;
 1221                         }
 1222                         break;
 1223 
 1224                 case 0x02:
 1225                         mpt_prt(mpt, "Port %d: FC Link Event: LPE(%02x,%02x) "
 1226                             "(Loop Port Enable)",
 1227                             (msg->Data[1] >> 8) & 0xff,
 1228                             (msg->Data[0] >> 8) & 0xff,
 1229                             (msg->Data[0]     ) & 0xff);
 1230                         break;
 1231 
 1232                 case 0x03:
 1233                         mpt_prt(mpt, "Port %d: FC Link Event: LPB(%02x,%02x) "
 1234                             "(Loop Port Bypass)",
 1235                             (msg->Data[1] >> 8) & 0xff,
 1236                             (msg->Data[0] >> 8) & 0xff,
 1237                             (msg->Data[0]     ) & 0xff);
 1238                         break;
 1239 
 1240                 default:
 1241                         mpt_prt(mpt, "Port %d: FC Link Event: "
 1242                             "Unknown event (%02x %02x %02x)",
 1243                             (msg->Data[1] >>  8) & 0xff,
 1244                             (msg->Data[0] >> 16) & 0xff,
 1245                             (msg->Data[0] >>  8) & 0xff,
 1246                             (msg->Data[0]      ) & 0xff);
 1247                         break;
 1248                 }
 1249                 break;
 1250 
 1251         case MPI_EVENT_LOGOUT:
 1252                 mpt_prt(mpt, "Port %d: FC Logout: N_PortID: %02x",
 1253                     (msg->Data[1] >> 8) & 0xff, msg->Data[0]);
 1254                 break;
 1255 
 1256         case MPI_EVENT_EVENT_CHANGE:
 1257                 /*
 1258                  * This is just an acknowledgement of our
 1259                  * mpt_send_event_request().
 1260                  */
 1261                 break;
 1262 
 1263         case MPI_EVENT_SAS_PHY_LINK_STATUS:
 1264                 switch ((msg->Data[0] >> 12) & 0x0f) {
 1265                 case 0x00:
 1266                         mpt_prt(mpt, "Phy %d: Link Status Unknown",
 1267                             msg->Data[0] & 0xff);
 1268                         break;
 1269                 case 0x01:
 1270                         mpt_prt(mpt, "Phy %d: Link Disabled",
 1271                             msg->Data[0] & 0xff);
 1272                         break;
 1273                 case 0x02:
 1274                         mpt_prt(mpt, "Phy %d: Failed Speed Negotiation",
 1275                             msg->Data[0] & 0xff);
 1276                         break;
 1277                 case 0x03:
 1278                         mpt_prt(mpt, "Phy %d: SATA OOB Complete",
 1279                             msg->Data[0] & 0xff);
 1280                         break;
 1281                 case 0x08:
 1282                         mpt_prt(mpt, "Phy %d: Link Rate 1.5 Gbps",
 1283                             msg->Data[0] & 0xff);
 1284                         break;
 1285                 case 0x09:
 1286                         mpt_prt(mpt, "Phy %d: Link Rate 3.0 Gbps",
 1287                             msg->Data[0] & 0xff);
 1288                         break;
 1289                 default:
 1290                         mpt_prt(mpt, "Phy %d: SAS Phy Link Status Event: "
 1291                             "Unknown event (%0x)",
 1292                             msg->Data[0] & 0xff, (msg->Data[0] >> 8) & 0xff);
 1293                 }
 1294                 break;
 1295 
 1296         case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
 1297         case MPI_EVENT_SAS_DISCOVERY:
 1298                 /* ignore these events for now */
 1299                 break;
 1300 
 1301         default:
 1302                 mpt_prt(mpt, "Unknown async event: 0x%x", msg->Event);
 1303                 break;
 1304         }
 1305 
 1306         if (msg->AckRequired) {
 1307                 MSG_EVENT_ACK *ackp;
 1308                 request_t *req;
 1309 
 1310                 if ((req = mpt_get_request(mpt)) == NULL) {
 1311                         /* XXX XXX XXX XXXJRT */
 1312                         panic("mpt_event_notify_reply: unable to allocate "
 1313                             "request structure");
 1314                 }
 1315 
 1316                 ackp = (MSG_EVENT_ACK *) req->req_vbuf;
 1317                 memset(ackp, 0, sizeof(*ackp));
 1318                 ackp->Function = MPI_FUNCTION_EVENT_ACK;
 1319                 ackp->Event = msg->Event;
 1320                 ackp->EventContext = msg->EventContext;
 1321                 ackp->MsgContext = htole32(req->index | 0x80000000);
 1322                 mpt_check_doorbell(mpt);
 1323                 mpt_send_cmd(mpt, req);
 1324         }
 1325 }
 1326 
 1327 /* XXXJRT mpt_bus_reset() */
 1328 
 1329 /*****************************************************************************
 1330  * SCSI interface routines
 1331  *****************************************************************************/
 1332 
 1333 static void
 1334 mpt_scsipi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req,
 1335     void *arg)
 1336 {
 1337         struct scsipi_adapter *adapt = chan->chan_adapter;
 1338         mpt_softc_t *mpt = (void *) adapt->adapt_dev;
 1339 
 1340         switch (req) {
 1341         case ADAPTER_REQ_RUN_XFER:
 1342                 mpt_run_xfer(mpt, (struct scsipi_xfer *) arg);
 1343                 return;
 1344 
 1345         case ADAPTER_REQ_GROW_RESOURCES:
 1346                 /* Not supported. */
 1347                 return;
 1348 
 1349         case ADAPTER_REQ_SET_XFER_MODE:
 1350                 mpt_set_xfer_mode(mpt, (struct scsipi_xfer_mode *) arg);
 1351                 return;
 1352         }
 1353 }
 1354 
 1355 static void
 1356 mpt_minphys(struct buf *bp)
 1357 {
 1358 
 1359 /*
 1360  * Subtract one from the SGL limit, since we need an extra one to handle
 1361  * an non-page-aligned transfer.
 1362  */
 1363 #define MPT_MAX_XFER    ((MPT_SGL_MAX - 1) * PAGE_SIZE)
 1364 
 1365         if (bp->b_bcount > MPT_MAX_XFER)
 1366                 bp->b_bcount = MPT_MAX_XFER;
 1367         minphys(bp);
 1368 }

Cache object: 64e0bb5576bc98e6b5182311ef85a3ad


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.