root/dev/i2o/iopsp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. iopsp_match
  2. iopsp_attach
  3. iopsp_reconfig
  4. iopsp_rescan
  5. iopspminphys
  6. iopsp_scsi_cmd
  7. iopsp_scsi_abort
  8. iopsp_intr
  9. iopsp_adjqparam

    1 /*      $OpenBSD: iopsp.c,v 1.9 2006/11/28 23:59:45 dlg Exp $   */
    2 /*      $NetBSD$        */
    3 
    4 /*-
    5  * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
    6  * All rights reserved.
    7  *
    8  * This code is derived from software contributed to The NetBSD Foundation
    9  * by Andrew Doran.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. All advertising materials mentioning features or use of this software
   20  *    must display the following acknowledgement:
   21  *        This product includes software developed by the NetBSD
   22  *        Foundation, Inc. and its contributors.
   23  * 4. Neither the name of The NetBSD Foundation nor the names of its
   24  *    contributors may be used to endorse or promote products derived
   25  *    from this software without specific prior written permission.
   26  *
   27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   37  * POSSIBILITY OF SUCH DAMAGE.
   38  */
   39 
   40 /*
   41  * Raw SCSI device support for I2O.  IOPs present SCSI devices individually;
   42  * we group them by controlling port.
   43  */
   44 
   45 #include <sys/param.h>
   46 #include <sys/systm.h>
   47 #include <sys/kernel.h>
   48 #include <sys/device.h>
   49 #include <sys/queue.h>
   50 #include <sys/proc.h>
   51 #include <sys/buf.h>
   52 #include <sys/endian.h>
   53 #include <sys/malloc.h>
   54 #include <sys/scsiio.h>
   55 #include <sys/lock.h>
   56 
   57 #include <machine/bus.h>
   58 
   59 #include <scsi/scsi_all.h>
   60 #include <scsi/scsi_disk.h>
   61 #include <scsi/scsi_all.h>
   62 #include <scsi/scsiconf.h>
   63 #include <scsi/scsi_message.h>
   64 
   65 #include <dev/i2o/i2o.h>
   66 #include <dev/i2o/iopio.h>
   67 #include <dev/i2o/iopvar.h>
   68 #include <dev/i2o/iopspvar.h>
   69 
   70 struct cfdriver iopsp_cd = {
   71         NULL, "iopsp", DV_DULL
   72 };
   73 
   74 int     iopsp_match(struct device *, void *, void *);
   75 void    iopsp_attach(struct device *, struct device *, void *);
   76 
   77 struct cfattach iopsp_ca = {
   78         sizeof(struct iopsp_softc), iopsp_match, iopsp_attach
   79 };
   80 
   81 int     iopsp_scsi_cmd(struct scsi_xfer *);
   82 void    iopspminphys(struct buf *bp);
   83 
   84 struct scsi_adapter iopsp_switch = {
   85         iopsp_scsi_cmd, iopspminphys, 0, 0,
   86 };
   87 
   88 struct scsi_device iopsp_dev = {
   89         NULL, NULL, NULL, NULL
   90 };
   91 
   92 void    iopsp_adjqparam(struct device *, int);
   93 void    iopsp_intr(struct device *, struct iop_msg *, void *);
   94 int     iopsp_rescan(struct iopsp_softc *);
   95 int     iopsp_reconfig(struct device *);
   96 
   97 /*
   98  * Match a supported device.
   99  */
  100 int
  101 iopsp_match(struct device *parent, void *match, void *aux)
  102 {
  103         struct iop_attach_args *ia = aux;
  104         struct {
  105                 struct  i2o_param_op_results pr;
  106                 struct  i2o_param_read_results prr;
  107                 struct  i2o_param_hba_ctlr_info ci;
  108         } __attribute__ ((__packed__)) param;
  109         int rv;
  110 
  111         if (ia->ia_class != I2O_CLASS_BUS_ADAPTER_PORT)
  112                 return (0);
  113 
  114         if ((rv = iop_param_op((struct iop_softc *)parent, ia->ia_tid, NULL, 0,
  115             I2O_PARAM_HBA_CTLR_INFO, &param, sizeof(param)))) {
  116 #ifdef I2ODEBUG
  117                 printf("iopsp_match: iop_param_op failed, status = %d\n", rv);
  118 #endif
  119                 return (0);
  120         }
  121 
  122 #ifdef I2ODEBUG
  123         printf("iopsp_match: bustype = %d\n", param.ci.bustype);
  124 #endif
  125 
  126         return (param.ci.bustype == I2O_HBA_BUS_SCSI ||
  127             param.ci.bustype == I2O_HBA_BUS_FCA);
  128 }
  129 
  130 /*
  131  * Attach a supported device.
  132  */
  133 void
  134 iopsp_attach(struct device *parent, struct device *self, void *aux)
  135 {
  136         struct iop_softc *iop = (struct iop_softc *)parent;
  137         struct iopsp_softc *sc = (struct iopsp_softc *)self;
  138         struct iop_attach_args *ia = (struct iop_attach_args *)aux;
  139         struct scsibus_attach_args saa;
  140         struct {
  141                 struct  i2o_param_op_results pr;
  142                 struct  i2o_param_read_results prr;
  143                 union {
  144                         struct  i2o_param_hba_ctlr_info ci;
  145                         struct  i2o_param_hba_scsi_ctlr_info sci;
  146                         struct  i2o_param_hba_scsi_port_info spi;
  147                 } p;
  148         } __attribute__ ((__packed__)) param;
  149         int fcal, rv;
  150 #ifdef I2OVERBOSE
  151         int size;
  152 #endif
  153 
  154         /* Register us as an initiator. */
  155         sc->sc_ii.ii_dv = self;
  156         sc->sc_ii.ii_intr = iopsp_intr;
  157         sc->sc_ii.ii_flags = 0;
  158         sc->sc_ii.ii_tid = ia->ia_tid;
  159         sc->sc_ii.ii_reconfig = iopsp_reconfig;
  160         sc->sc_ii.ii_adjqparam = iopsp_adjqparam;
  161         iop_initiator_register(iop, &sc->sc_ii);
  162 
  163         rv = iop_param_op(iop, ia->ia_tid, NULL, 0, I2O_PARAM_HBA_CTLR_INFO,
  164             &param, sizeof(param));
  165         if (rv != 0) {
  166                 printf("%s: unable to get parameters (0x%04x; %d)\n",
  167                     sc->sc_dv.dv_xname, I2O_PARAM_HBA_CTLR_INFO, rv);
  168                 goto bad;
  169         }
  170 
  171         fcal = (param.p.ci.bustype == I2O_HBA_BUS_FCA);         /* XXX */
  172 
  173         /* 
  174          * Say what the device is.  If we can find out what the controling
  175          * device is, say what that is too.
  176          */
  177         printf(": SCSI port");
  178         iop_print_ident(iop, ia->ia_tid);
  179         printf("\n");
  180 
  181         rv = iop_param_op(iop, ia->ia_tid, NULL, 0,
  182             I2O_PARAM_HBA_SCSI_CTLR_INFO, &param, sizeof(param));
  183         if (rv != 0) {
  184                 printf("%s: unable to get parameters (0x%04x; %d)\n",
  185                     sc->sc_dv.dv_xname, I2O_PARAM_HBA_SCSI_CTLR_INFO, rv);
  186                 goto bad;
  187         }
  188 
  189 #ifdef I2OVERBOSE
  190         printf("%s: %d-bit, max sync rate %dMHz, initiator ID %d\n",
  191             sc->sc_dv.dv_xname, param.p.sci.maxdatawidth,
  192             (u_int32_t)letoh64(param.p.sci.maxsyncrate) / 1000,
  193             letoh32(param.p.sci.initiatorid));
  194 #endif
  195 
  196         sc->sc_link.adapter_softc = sc;
  197         sc->sc_link.adapter = &iopsp_switch;
  198         sc->sc_link.adapter_target = letoh32(param.p.sci.initiatorid);
  199         sc->sc_link.device = &iopsp_dev;
  200         sc->sc_link.openings = 1;
  201         sc->sc_link.adapter_buswidth = fcal?
  202             IOPSP_MAX_FCAL_TARGET : param.p.sci.maxdatawidth;
  203         sc->sc_link.luns = IOPSP_MAX_LUN;
  204 
  205 #ifdef I2OVERBOSE
  206         /*
  207          * Allocate the target map.  Currently used for informational
  208          * purposes only.
  209          */
  210         size = sc->sc_link.adapter_buswidth * sizeof(struct iopsp_target);
  211         sc->sc_targetmap = malloc(size, M_DEVBUF, M_NOWAIT);
  212         bzero(sc->sc_targetmap, size);
  213 #endif
  214 
  215         /* Build the two maps, and attach to scsi. */
  216         if (iopsp_reconfig(self) != 0) {
  217                 printf("%s: configure failed\n", sc->sc_dv.dv_xname);
  218                 goto bad;
  219         }
  220 
  221         bzero(&saa, sizeof(saa));
  222         saa.saa_sc_link = &sc->sc_link;
  223 
  224         config_found(&sc->sc_dv, &saa, scsiprint);
  225         return;
  226 
  227  bad:
  228         iop_initiator_unregister(iop, &sc->sc_ii);
  229 }
  230 
  231 /*
  232  * Scan the LCT to determine which devices we control, and enter them into
  233  * the maps.
  234  */
  235 int
  236 iopsp_reconfig(struct device *dv)
  237 {
  238         struct iopsp_softc *sc = (struct iopsp_softc *)dv;
  239         struct iop_softc *iop = (struct iop_softc *)sc->sc_dv.dv_parent;
  240         struct i2o_lct_entry *le;
  241         struct {
  242                 struct  i2o_param_op_results pr;
  243                 struct  i2o_param_read_results prr;
  244                 struct  i2o_param_scsi_device_info sdi;
  245         } __attribute__ ((__packed__)) param;
  246         u_int tid, nent, i, targ, lun, size, s, rv, bptid;
  247         u_short *tidmap;
  248 #ifdef I2OVERBOSE
  249         struct iopsp_target *it;
  250         int syncrate;   
  251 #endif
  252 
  253         /* Anything to do? */
  254         if (iop->sc_chgind == sc->sc_chgind)
  255                 return (0);
  256 
  257         /*
  258          * Allocate memory for the target/LUN -> TID map.  Use zero to
  259          * denote absent targets (zero is the TID of the I2O executive,
  260          * and we never address that here).
  261          */
  262         size = sc->sc_link.adapter_buswidth * IOPSP_MAX_LUN * sizeof(u_short);
  263         if (!(tidmap = malloc(size, M_DEVBUF, M_NOWAIT)))
  264                 return (ENOMEM);
  265         bzero(tidmap, size);
  266 
  267 #ifdef I2OVERBOSE
  268         for (i = 0; i < sc->sc_link.adapter_buswidth; i++)
  269                 sc->sc_targetmap[i].it_flags &= ~IT_PRESENT;
  270 #endif
  271 
  272         /*
  273          * A quick hack to handle Intel's stacked bus port arrangement.
  274          */
  275         bptid = sc->sc_ii.ii_tid;
  276         nent = iop->sc_nlctent;
  277         for (le = iop->sc_lct->entry; nent != 0; nent--, le++)
  278                 if ((letoh16(le->classid) & 4095) ==
  279                     I2O_CLASS_BUS_ADAPTER_PORT &&
  280                     (letoh32(le->usertid) & 4095) == bptid) {
  281                         bptid = letoh16(le->localtid) & 4095;
  282                         break;
  283                 }
  284 
  285         nent = iop->sc_nlctent;
  286         for (i = 0, le = iop->sc_lct->entry; i < nent; i++, le++) {
  287                 if ((letoh16(le->classid) & I2O_CLASS_MASK) !=
  288                     I2O_CLASS_SCSI_PERIPHERAL ||
  289                     ((letoh32(le->usertid) >> 12) & 4095) != bptid)
  290                         continue;
  291                 tid = letoh16(le->localtid) & I2O_LCT_ENTRY_TID_MASK;
  292 
  293                 rv = iop_param_op(iop, tid, NULL, 0, I2O_PARAM_SCSI_DEVICE_INFO,
  294                     &param, sizeof(param));
  295                 if (rv != 0) {
  296                         printf("%s: unable to get parameters (0x%04x; %d)\n",
  297                             sc->sc_dv.dv_xname, I2O_PARAM_SCSI_DEVICE_INFO,
  298                             rv);
  299                         continue;
  300                 }
  301                 targ = letoh32(param.sdi.identifier);
  302                 lun = param.sdi.luninfo[1];
  303 #if defined(DIAGNOSTIC) || defined(I2ODEBUG)
  304                 if (targ >= sc->sc_link.adapter_buswidth ||
  305                     lun >= sc->sc_link.adapter_buswidth) {
  306                         printf("%s: target %d,%d (tid %d): bad target/LUN\n",
  307                             sc->sc_dv.dv_xname, targ, lun, tid);
  308                         continue;
  309                 }
  310 #endif
  311 
  312 #ifdef I2OVERBOSE
  313                 /*
  314                  * If we've already described this target, and nothing has
  315                  * changed, then don't describe it again.
  316                  */
  317                 it = &sc->sc_targetmap[targ];
  318                 it->it_flags |= IT_PRESENT;
  319                 syncrate = (int)((letoh64(param.sdi.negsyncrate) + 500) / 1000);
  320                 if (it->it_width == param.sdi.negdatawidth &&
  321                     it->it_offset == param.sdi.negoffset &&
  322                     it->it_syncrate == syncrate)
  323                         continue;
  324 
  325                 it->it_width = param.sdi.negdatawidth;
  326                 it->it_offset = param.sdi.negoffset;
  327                 it->it_syncrate = syncrate;
  328 
  329                 printf("%s: target %d (tid %d): %d-bit, ", sc->sc_dv.dv_xname,
  330                     targ, tid, it->it_width);
  331                 if (it->it_syncrate == 0)
  332                         printf("asynchronous\n");
  333                 else
  334                         printf("synchronous at %dMHz, offset 0x%x\n",
  335                             it->it_syncrate, it->it_offset);
  336 #endif
  337 
  338                 /* Ignore the device if it's in use by somebody else. */
  339                 if ((letoh32(le->usertid) & 4095) != I2O_TID_NONE) {
  340 #ifdef I2OVERBOSE
  341                         if (sc->sc_tidmap == NULL ||
  342                             IOPSP_TIDMAP(sc->sc_tidmap, targ, lun) !=
  343                             IOPSP_TID_INUSE)
  344                                 printf("%s: target %d,%d (tid %d): in use by"
  345                                     " tid %d\n", sc->sc_dv.dv_xname,
  346                                     targ, lun, tid,
  347                                     letoh32(le->usertid) & 4095);
  348 #endif
  349                         IOPSP_TIDMAP(tidmap, targ, lun) = IOPSP_TID_INUSE;
  350                 } else
  351                         IOPSP_TIDMAP(tidmap, targ, lun) = (u_short)tid;
  352         }
  353 
  354 #ifdef I2OVERBOSE
  355         for (i = 0; i < sc->sc_link.adapter_buswidth; i++)
  356                 if ((sc->sc_targetmap[i].it_flags & IT_PRESENT) == 0)
  357                         sc->sc_targetmap[i].it_width = 0;
  358 #endif
  359 
  360         /* Swap in the new map and return. */
  361         s = splbio();
  362         if (sc->sc_tidmap != NULL)
  363                 free(sc->sc_tidmap, M_DEVBUF);
  364         sc->sc_tidmap = tidmap;
  365         splx(s);
  366         sc->sc_chgind = iop->sc_chgind;
  367         return (0);
  368 }
  369 
  370 /*
  371  * Re-scan the bus; to be called from a higher level (e.g. scsi).
  372  */
  373 int
  374 iopsp_rescan(struct iopsp_softc *sc)
  375 {
  376         struct iop_softc *iop;
  377         struct iop_msg *im;
  378         struct i2o_hba_bus_scan mf;
  379         int rv;
  380 
  381         iop = (struct iop_softc *)sc->sc_dv.dv_parent;
  382 
  383         rv = lockmgr(&iop->sc_conflock, LK_EXCLUSIVE, NULL);
  384         if (rv != 0) {
  385 #ifdef I2ODEBUG
  386                 printf("iopsp_rescan: unable to acquire lock\n");
  387 #endif
  388                 return (rv);
  389         }
  390 
  391         im = iop_msg_alloc(iop, &sc->sc_ii, IM_WAIT);
  392 
  393         mf.msgflags = I2O_MSGFLAGS(i2o_hba_bus_scan);
  394         mf.msgfunc = I2O_MSGFUNC(sc->sc_ii.ii_tid, I2O_HBA_BUS_SCAN);
  395         mf.msgictx = sc->sc_ii.ii_ictx;
  396         mf.msgtctx = im->im_tctx;
  397 
  398         rv = iop_msg_post(iop, im, &mf, 5*60*1000);
  399         iop_msg_free(iop, im);
  400         if (rv != 0)
  401                 printf("%s: bus rescan failed (error %d)\n",
  402                     sc->sc_dv.dv_xname, rv);
  403 
  404         if ((rv = iop_lct_get(iop)) == 0)
  405                 rv = iopsp_reconfig(&sc->sc_dv);
  406 
  407         lockmgr(&iop->sc_conflock, LK_RELEASE, NULL);
  408         return (rv);
  409 }
  410 
  411 void
  412 iopspminphys(bp)
  413         struct buf *bp;
  414 {
  415         if (bp->b_bcount > IOP_MAX_XFER)
  416                 bp->b_bcount = IOP_MAX_XFER;
  417         minphys(bp);
  418 }
  419 
  420 /*
  421  * Start a SCSI command.
  422  */
  423 int
  424 iopsp_scsi_cmd(xs)
  425         struct scsi_xfer *xs;
  426 {
  427         struct scsi_link *link = xs->sc_link;
  428         struct iopsp_softc *sc = (struct iopsp_softc *)link->adapter_softc;
  429         struct iop_softc *iop = (struct iop_softc *)sc->sc_dv.dv_parent;
  430         struct iop_msg *im;
  431         struct i2o_scsi_scb_exec *mf;
  432         int error, tid, s;
  433         u_int32_t mb[IOP_MAX_MSG_SIZE / sizeof(u_int32_t)];
  434 
  435         tid = IOPSP_TIDMAP(sc->sc_tidmap, link->target, link->lun);
  436         if (tid == IOPSP_TID_ABSENT || tid == IOPSP_TID_INUSE) {
  437                 xs->error = XS_SELTIMEOUT;
  438                 scsi_done(xs);
  439                 return (COMPLETE);
  440         }
  441 
  442         SC_DEBUG(xs->sc_link, SDEV_DB2, ("iopsp_scsi_cmd: run_xfer\n"));
  443 
  444         /* Need to reset the target? */
  445         if ((xs->flags & XS_RESET) != 0) {
  446                 if (iop_simple_cmd(iop, tid, I2O_SCSI_DEVICE_RESET,
  447                     sc->sc_ii.ii_ictx, 1, 30*1000) != 0) {
  448 #ifdef I2ODEBUG
  449                         printf("%s: reset failed\n",
  450                             sc->sc_dv.dv_xname);
  451 #endif
  452                         xs->error = XS_DRIVER_STUFFUP;
  453                 } else
  454                         xs->error = XS_NOERROR;
  455 
  456                 scsi_done(xs);
  457                 return (COMPLETE);
  458         }
  459 
  460 #if defined(I2ODEBUG) || defined(SCSIDEBUG)
  461         if (xs->cmdlen > sizeof(mf->cdb))
  462                 panic("%s: CDB too large", sc->sc_dv.dv_xname);
  463 #endif
  464 
  465         im = iop_msg_alloc(iop, &sc->sc_ii, IM_POLL_INTR |
  466             IM_NOSTATUS | ((xs->flags & SCSI_POLL) != 0 ? IM_POLL : 0));
  467         im->im_dvcontext = xs;
  468 
  469         mf = (struct i2o_scsi_scb_exec *)mb;
  470         mf->msgflags = I2O_MSGFLAGS(i2o_scsi_scb_exec);
  471         mf->msgfunc = I2O_MSGFUNC(tid, I2O_SCSI_SCB_EXEC);
  472         mf->msgictx = sc->sc_ii.ii_ictx;
  473         mf->msgtctx = im->im_tctx;
  474         mf->flags = xs->cmdlen | I2O_SCB_FLAG_ENABLE_DISCONNECT |
  475             I2O_SCB_FLAG_SENSE_DATA_IN_MESSAGE;
  476         mf->datalen = xs->datalen;
  477         memcpy(mf->cdb, xs->cmd, xs->cmdlen);
  478 
  479 #if 0
  480         switch (xs->xs_tag_type) {
  481         case MSG_ORDERED_Q_TAG:
  482                 mf->flags |= I2O_SCB_FLAG_ORDERED_QUEUE_TAG;
  483                 break;
  484         case MSG_SIMPLE_Q_TAG:
  485                 mf->flags |= I2O_SCB_FLAG_SIMPLE_QUEUE_TAG;
  486                 break;
  487         case MSG_HEAD_OF_Q_TAG:
  488                 mf->flags |= I2O_SCB_FLAG_HEAD_QUEUE_TAG;
  489                 break;
  490         default:
  491                 break;
  492         }
  493 #endif
  494 
  495         if (xs->datalen != 0) {
  496                 error = iop_msg_map_bio(iop, im, mb, xs->data,
  497                     xs->datalen, (xs->flags & SCSI_DATA_OUT) == 0);
  498                 if (error) {
  499                         xs->error = XS_DRIVER_STUFFUP;
  500                         iop_msg_free(iop, im);
  501                         scsi_done(xs);
  502                         return (COMPLETE);
  503                 }
  504                 if ((xs->flags & SCSI_DATA_IN) == 0)
  505                         mf->flags |= I2O_SCB_FLAG_XFER_TO_DEVICE;
  506                 else
  507                         mf->flags |= I2O_SCB_FLAG_XFER_FROM_DEVICE;
  508         }
  509 
  510         s = splbio();
  511         sc->sc_curqd++;
  512         splx(s);
  513 
  514         if (iop_msg_post(iop, im, mb, xs->timeout)) {
  515                 s = splbio();
  516                 sc->sc_curqd--;
  517                 splx(s);
  518                 if (xs->datalen != 0)
  519                         iop_msg_unmap(iop, im);
  520                 iop_msg_free(iop, im);
  521                 xs->error = XS_DRIVER_STUFFUP;
  522                 scsi_done(xs);
  523                 return (COMPLETE);
  524         }
  525 
  526         return (xs->flags & SCSI_POLL? COMPLETE : SUCCESSFULLY_QUEUED);
  527 }
  528 
  529 #ifdef notyet
  530 /*
  531  * Abort the specified I2O_SCSI_SCB_EXEC message and its associated SCB.
  532  */
  533 int
  534 iopsp_scsi_abort(struct iopsp_softc *sc, int atid, struct iop_msg *aim)
  535 {
  536         struct iop_msg *im;
  537         struct i2o_scsi_scb_abort mf;
  538         struct iop_softc *iop;
  539         int rv, s;
  540 
  541         iop = (struct iop_softc *)sc->sc_dv.dv_parent;
  542         im = iop_msg_alloc(iop, &sc->sc_ii, IM_POLL);
  543 
  544         mf.msgflags = I2O_MSGFLAGS(i2o_scsi_scb_abort);
  545         mf.msgfunc = I2O_MSGFUNC(atid, I2O_SCSI_SCB_ABORT);
  546         mf.msgictx = sc->sc_ii.ii_ictx;
  547         mf.msgtctx = im->im_tctx;
  548         mf.tctxabort = aim->im_tctx;
  549 
  550         s = splbio();
  551         rv = iop_msg_post(iop, im, &mf, 30000);
  552         splx(s);
  553         iop_msg_free(iop, im);
  554         return (rv);
  555 }
  556 #endif
  557 
  558 /*
  559  * We have a message which has been processed and replied to by the IOP -
  560  * deal with it.
  561  */
  562 void
  563 iopsp_intr(struct device *dv, struct iop_msg *im, void *reply)
  564 {
  565         struct scsi_xfer *xs;
  566         struct iopsp_softc *sc;
  567         struct i2o_scsi_reply *rb;
  568         struct iop_softc *iop;
  569         u_int sl;
  570 
  571         sc = (struct iopsp_softc *)dv;
  572         xs = (struct scsi_xfer *)im->im_dvcontext;
  573         iop = (struct iop_softc *)dv->dv_parent;
  574         rb = reply;
  575 
  576         SC_DEBUG(xs->sc_link, SDEV_DB2, ("iopsp_intr\n"));
  577 
  578         if ((rb->msgflags & I2O_MSGFLAGS_FAIL) != 0) {
  579                 xs->error = XS_DRIVER_STUFFUP;
  580                 xs->resid = xs->datalen;
  581         } else {
  582                 if (rb->hbastatus != I2O_SCSI_DSC_SUCCESS) {
  583                         switch (rb->hbastatus) {
  584                         case I2O_SCSI_DSC_ADAPTER_BUSY:
  585                         case I2O_SCSI_DSC_SCSI_BUS_RESET:
  586                         case I2O_SCSI_DSC_BUS_BUSY:
  587                                 xs->error = XS_BUSY;
  588                                 break;
  589                         case I2O_SCSI_DSC_SELECTION_TIMEOUT:
  590                                 xs->error = XS_SELTIMEOUT;
  591                                 break;
  592                         case I2O_SCSI_DSC_COMMAND_TIMEOUT:
  593                         case I2O_SCSI_DSC_DEVICE_NOT_PRESENT:
  594                         case I2O_SCSI_DSC_LUN_INVALID:
  595                         case I2O_SCSI_DSC_SCSI_TID_INVALID:
  596                                 xs->error = XS_TIMEOUT;
  597                                 break;
  598                         default:
  599                                 xs->error = XS_DRIVER_STUFFUP;
  600                                 break;
  601                         }
  602                         printf("%s: HBA status 0x%02x\n", sc->sc_dv.dv_xname,
  603                            rb->hbastatus);
  604                 } else if (rb->scsistatus != SCSI_OK) {
  605                         switch (rb->scsistatus) {
  606                         case SCSI_CHECK:
  607                                 xs->error = XS_SENSE;
  608                                 sl = letoh32(rb->senselen);
  609                                 if (sl > sizeof(xs->sense))
  610                                         sl = sizeof(xs->sense);
  611                                 bcopy(rb->sense, &xs->sense, sl);
  612                                 break;
  613                         case SCSI_QUEUE_FULL:
  614                         case SCSI_BUSY:
  615                                 xs->error = XS_BUSY;
  616                                 break;
  617                         default:
  618                                 xs->error = XS_DRIVER_STUFFUP;
  619                                 break;
  620                         }
  621                 } else
  622                         xs->error = XS_NOERROR;
  623 
  624                 xs->resid = xs->datalen - letoh32(rb->datalen);
  625                 xs->status = rb->scsistatus;
  626         }
  627 
  628         /* Free the message wrapper and pass the news to scsi. */
  629         if (xs->datalen != 0)
  630                 iop_msg_unmap(iop, im);
  631         iop_msg_free(iop, im);
  632 
  633         if (--sc->sc_curqd == sc->sc_link.openings)
  634                 wakeup(&sc->sc_curqd);
  635 
  636         scsi_done(xs);
  637 }
  638 
  639 /*
  640  * The number of openings available to us has changed, so inform scsi.
  641  */
  642 void
  643 iopsp_adjqparam(struct device *dv, int mpi)
  644 {
  645         struct iopsp_softc *sc = (struct iopsp_softc *)dv;
  646         int s;
  647 
  648         s = splbio();
  649         sc->sc_link.openings = mpi;
  650         if (mpi < sc->sc_curqd)
  651                 tsleep(&sc->sc_curqd, PWAIT, "iopspdrn", 0);
  652         splx(s);
  653 }

/* [<][>][^][v][top][bottom][index][help] */