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/aic79xx_osm.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: aic79xx_osm.c,v 1.12.2.2 2005/12/07 18:20:02 tron Exp $        */
    2 
    3 /*
    4  * Bus independent NetBSD shim for the aic7xxx based adaptec SCSI controllers
    5  *
    6  * Copyright (c) 1994-2002 Justin T. Gibbs.
    7  * Copyright (c) 2001-2002 Adaptec Inc.
    8  * All rights reserved.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions, and the following disclaimer,
   15  *    without modification.
   16  * 2. The name of the author may not be used to endorse or promote products
   17  *    derived from this software without specific prior written permission.
   18  *
   19  * Alternatively, this software may be distributed under the terms of the
   20  * GNU Public License ("GPL").
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   26  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  *
   34  * //depot/aic7xxx/freebsd/dev/aic7xxx/aic79xx_osm.c#26 $
   35  *
   36  * $FreeBSD: src/sys/dev/aic7xxx/aic79xx_osm.c,v 1.11 2003/05/04 00:20:07 gibbs Exp $
   37  */
   38 /*
   39  * Ported from FreeBSD by Pascal Renauld, Network Storage Solutions, Inc.
   40  * - April 2003
   41  */
   42 
   43 #include <sys/cdefs.h>
   44 __KERNEL_RCSID(0, "$NetBSD: aic79xx_osm.c,v 1.12.2.2 2005/12/07 18:20:02 tron Exp $");
   45 
   46 #include <dev/ic/aic79xx_osm.h>
   47 #include <dev/ic/aic7xxx_cam.h>
   48 #include <dev/ic/aic79xx_inline.h>
   49 
   50 #ifndef AHD_TMODE_ENABLE
   51 #define AHD_TMODE_ENABLE 0
   52 #endif
   53 
   54 static int      ahd_ioctl(struct scsipi_channel *channel, u_long cmd,
   55                           caddr_t addr, int flag, struct proc *p);
   56 static void     ahd_action(struct scsipi_channel *chan,
   57                            scsipi_adapter_req_t req, void *arg);
   58 static void     ahd_execute_scb(void *arg, bus_dma_segment_t *dm_segs,
   59                                 int nsegments);
   60 static int      ahd_poll(struct ahd_softc *ahd, int wait);
   61 static void     ahd_setup_data(struct ahd_softc *ahd, struct scsipi_xfer *xs,
   62                                struct scb *scb);
   63 
   64 #if NOT_YET
   65 static void     ahd_set_recoveryscb(struct ahd_softc *ahd, struct scb *scb);
   66 #endif
   67 
   68 /*
   69  * Attach all the sub-devices we can find
   70  */
   71 int
   72 ahd_attach(struct ahd_softc *ahd)
   73 {
   74         int     s;
   75         char    ahd_info[256];
   76 
   77         ahd_controller_info(ahd, ahd_info, sizeof(ahd_info));
   78         printf("%s: %s\n", ahd->sc_dev.dv_xname, ahd_info);
   79 
   80         ahd_lock(ahd, &s);
   81 
   82         ahd->sc_adapter.adapt_dev = &ahd->sc_dev;
   83         ahd->sc_adapter.adapt_nchannels = 1;
   84 
   85         ahd->sc_adapter.adapt_openings = ahd->scb_data.numscbs - 1;
   86         ahd->sc_adapter.adapt_max_periph = 32;
   87 
   88         ahd->sc_adapter.adapt_ioctl = ahd_ioctl;
   89         ahd->sc_adapter.adapt_minphys = ahd_minphys;
   90         ahd->sc_adapter.adapt_request = ahd_action;
   91 
   92         ahd->sc_channel.chan_adapter = &ahd->sc_adapter;
   93         ahd->sc_channel.chan_bustype = &scsi_bustype;
   94         ahd->sc_channel.chan_channel = 0;
   95         ahd->sc_channel.chan_ntargets = AHD_NUM_TARGETS;
   96         ahd->sc_channel.chan_nluns = 8 /*AHD_NUM_LUNS*/;
   97         ahd->sc_channel.chan_id = ahd->our_id;
   98         ahd->sc_channel.chan_flags |= SCSIPI_CHAN_CANGROW;
   99 
  100         ahd->sc_child = config_found((void *)ahd, &ahd->sc_channel, scsiprint);
  101 
  102         ahd_intr_enable(ahd, TRUE);
  103 
  104         if (ahd->flags & AHD_RESET_BUS_A)
  105                 ahd_reset_channel(ahd, 'A', TRUE);
  106 
  107         ahd_unlock(ahd, &s);
  108 
  109         return (1);
  110 }
  111 
  112 static int
  113 ahd_ioctl(struct scsipi_channel *channel, u_long cmd,
  114           caddr_t addr, int flag, struct proc *p)
  115 {
  116         struct ahd_softc *ahd = (void *)channel->chan_adapter->adapt_dev;
  117         int s, ret = ENOTTY;
  118 
  119         switch (cmd) {
  120         case SCBUSIORESET:
  121                 s = splbio();
  122                 ahd_reset_channel(ahd, channel->chan_channel == 1 ? 'B' : 'A', TRUE);
  123                 splx(s);
  124                 ret = 0;
  125                 break;
  126         default:
  127                 break;
  128         }
  129 
  130         return ret;
  131 }
  132 
  133 /*
  134  * Catch an interrupt from the adapter
  135  */
  136 void
  137 ahd_platform_intr(void *arg)
  138 {
  139         struct  ahd_softc *ahd;
  140 
  141         ahd = (struct ahd_softc *)arg;
  142 
  143         printf("%s; ahd_platform_intr\n", ahd_name(ahd));
  144 
  145         ahd_intr(ahd);
  146 }
  147 
  148 /*
  149  * We have an scb which has been processed by the
  150  * adaptor, now we look to see how the operation * went.
  151  */
  152 void
  153 ahd_done(struct ahd_softc *ahd, struct scb *scb)
  154 {
  155         struct scsipi_xfer      *xs;
  156         struct scsipi_periph    *periph;
  157         int                     s;
  158 
  159         LIST_REMOVE(scb, pending_links);
  160 
  161         xs = scb->xs;
  162         periph = xs->xs_periph;
  163 
  164         callout_stop(&scb->xs->xs_callout);
  165 
  166         if (xs->datalen) {
  167                 int op;
  168 
  169                 if (xs->xs_control & XS_CTL_DATA_IN)
  170                   op = BUS_DMASYNC_POSTREAD;
  171                 else
  172                   op = BUS_DMASYNC_POSTWRITE;
  173 
  174                 bus_dmamap_sync(ahd->parent_dmat, scb->dmamap, 0,
  175                                 scb->dmamap->dm_mapsize, op);
  176                 bus_dmamap_unload(ahd->parent_dmat, scb->dmamap);
  177         }
  178 
  179         /*
  180          * If the recovery SCB completes, we have to be
  181          * out of our timeout.
  182          */
  183         if ((scb->flags & SCB_RECOVERY_SCB) != 0) {
  184                 struct  scb *list_scb;
  185 
  186                 /*
  187                  * We were able to complete the command successfully,
  188                  * so reinstate the timeouts for all other pending
  189                  * commands.
  190                  */
  191                 LIST_FOREACH(list_scb, &ahd->pending_scbs, pending_links) {
  192                         struct scsipi_xfer      *txs = list_scb->xs;
  193 
  194                         if (!(txs->xs_control & XS_CTL_POLL)) {
  195                                 callout_reset(&txs->xs_callout,
  196                                     (txs->timeout > 1000000) ?
  197                                     (txs->timeout / 1000) * hz :
  198                                     (txs->timeout * hz) / 1000,
  199                                     ahd_timeout, list_scb);
  200                         }
  201                 }
  202 
  203                 if (ahd_get_transaction_status(scb) != XS_NOERROR)
  204                   ahd_set_transaction_status(scb, XS_TIMEOUT);
  205                 scsipi_printaddr(xs->xs_periph);
  206                 printf("%s: no longer in timeout, status = %x\n",
  207                        ahd_name(ahd), xs->status);
  208         }
  209 
  210         if (xs->error != XS_NOERROR) {
  211                 /* Don't clobber any existing error state */
  212         } else if ((xs->status == SCSI_STATUS_BUSY) ||
  213                    (xs->status == SCSI_STATUS_QUEUE_FULL)) {
  214                 ahd_set_transaction_status(scb, XS_BUSY);
  215                 printf("%s: drive (ID %d, LUN %d) queue full (SCB 0x%x)\n",
  216                        ahd_name(ahd), SCB_GET_TARGET(ahd,scb), SCB_GET_LUN(scb), SCB_GET_TAG(scb));
  217         } else if ((scb->flags & SCB_SENSE) != 0) {
  218                 /*
  219                  * We performed autosense retrieval.
  220                  *
  221                  * zero the sense data before having
  222                  * the drive fill it.  The SCSI spec mandates
  223                  * that any untransferred data should be
  224                  * assumed to be zero.  Complete the 'bounce'
  225                  * of sense information through buffers accessible
  226                  * via bus-space by copying it into the clients
  227                  * csio.
  228                  */
  229                 memset(&xs->sense.scsi_sense, 0, sizeof(xs->sense.scsi_sense));
  230                 memcpy(&xs->sense.scsi_sense, ahd_get_sense_buf(ahd, scb),
  231                        sizeof(struct scsi_sense_data));
  232 
  233                 ahd_set_transaction_status(scb, XS_SENSE);
  234         } else if ((scb->flags & SCB_PKT_SENSE) != 0) {
  235                 struct scsi_status_iu_header *siu;
  236                 u_int sense_len;
  237 #ifdef AHD_DEBUG
  238                 int i;
  239 #endif
  240                 /*
  241                  * Copy only the sense data into the provided buffer.
  242                  */
  243                 siu = (struct scsi_status_iu_header *)scb->sense_data;
  244                 sense_len = MIN(scsi_4btoul(siu->sense_length),
  245                                 sizeof(xs->sense.scsi_sense));
  246                 memset(&xs->sense.scsi_sense, 0, sizeof(xs->sense.scsi_sense));
  247                 memcpy(&xs->sense.scsi_sense,
  248                        scb->sense_data + SIU_SENSE_OFFSET(siu), sense_len);
  249 #ifdef AHD_DEBUG
  250                 printf("Copied %d bytes of sense data offset %d:", sense_len,
  251                        SIU_SENSE_OFFSET(siu));
  252                 for (i = 0; i < sense_len; i++)
  253                         printf(" 0x%x", ((uint8_t *)&xs->sense.scsi_sense)[i]);
  254                 printf("\n");
  255 #endif
  256                 ahd_set_transaction_status(scb, XS_SENSE);
  257         }
  258 
  259         if (scb->flags & SCB_FREEZE_QUEUE) {
  260                 scsipi_periph_thaw(periph, 1);
  261                 scb->flags &= ~SCB_FREEZE_QUEUE;
  262         }
  263 
  264         if (scb->flags & SCB_REQUEUE)
  265                 ahd_set_transaction_status(scb, XS_REQUEUE);
  266 
  267         ahd_lock(ahd, &s);
  268         ahd_free_scb(ahd, scb);
  269         ahd_unlock(ahd, &s);
  270 
  271         scsipi_done(xs);
  272 }
  273 
  274 static void
  275 ahd_action(struct scsipi_channel *chan, scsipi_adapter_req_t req, void *arg)
  276 {
  277         struct ahd_softc *ahd;
  278         struct ahd_initiator_tinfo *tinfo;
  279         struct ahd_tmode_tstate *tstate;
  280 
  281         ahd = (void *)chan->chan_adapter->adapt_dev;
  282 
  283         switch(req) {
  284 
  285         case ADAPTER_REQ_RUN_XFER:
  286           {
  287                 struct scsipi_xfer *xs;
  288                 struct scsipi_periph *periph;
  289                 struct scb *scb;
  290                 struct hardware_scb *hscb;
  291                 u_int target_id;
  292                 u_int our_id;
  293                 u_int col_idx;
  294                 char channel;
  295                 int s;
  296 
  297                 xs = arg;
  298                 periph = xs->xs_periph;
  299 
  300                 SC_DEBUG(periph, SCSIPI_DB3, ("ahd_action\n"));
  301 
  302                 target_id = periph->periph_target;
  303                 our_id = ahd->our_id;
  304                 channel = (chan->chan_channel == 1) ? 'B' : 'A';
  305 
  306                 /*
  307                  * get an scb to use.
  308                  */
  309                 ahd_lock(ahd, &s);
  310                 tinfo = ahd_fetch_transinfo(ahd, channel, our_id,
  311                                             target_id, &tstate);
  312 
  313                 if (xs->xs_tag_type != 0 ||
  314                     (tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0)
  315                         col_idx = AHD_NEVER_COL_IDX;
  316                 else
  317                         col_idx = AHD_BUILD_COL_IDX(target_id,
  318                             periph->periph_lun);
  319 
  320                 if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) {
  321                         xs->error = XS_RESOURCE_SHORTAGE;
  322                         ahd_unlock(ahd, &s);
  323                         scsipi_done(xs);
  324                         return;
  325                 }
  326                 ahd_unlock(ahd, &s);
  327 
  328                 hscb = scb->hscb;
  329 
  330                 SC_DEBUG(periph, SCSIPI_DB3, ("start scb(%p)\n", scb));
  331                 scb->xs = xs;
  332 
  333                 /*
  334                  * Put all the arguments for the xfer in the scb
  335                  */
  336                 hscb->control = 0;
  337                 hscb->scsiid = BUILD_SCSIID(ahd, sim, target_id, our_id);
  338                 hscb->lun = periph->periph_lun;
  339                 if (xs->xs_control & XS_CTL_RESET) {
  340                         hscb->cdb_len = 0;
  341                         scb->flags |= SCB_DEVICE_RESET;
  342                         hscb->control |= MK_MESSAGE;
  343                         hscb->task_management = SIU_TASKMGMT_LUN_RESET;
  344                         ahd_execute_scb(scb, NULL, 0);
  345                 } else {
  346                         hscb->task_management = 0;
  347                 }
  348 
  349                 ahd_setup_data(ahd, xs, scb);
  350                 break;
  351           }
  352 
  353         case ADAPTER_REQ_GROW_RESOURCES:
  354 #ifdef AHC_DEBUG
  355                 printf("%s: ADAPTER_REQ_GROW_RESOURCES\n", ahd_name(ahd));
  356 #endif
  357                 chan->chan_adapter->adapt_openings += ahd_alloc_scbs(ahd);
  358                 if (ahd->scb_data.numscbs >= AHD_SCB_MAX_ALLOC)
  359                         chan->chan_flags &= ~SCSIPI_CHAN_CANGROW;
  360                 break;
  361 
  362         case ADAPTER_REQ_SET_XFER_MODE:
  363             {
  364                 struct scsipi_xfer_mode *xm = arg;
  365                 struct ahd_devinfo devinfo;
  366                 int target_id, our_id, first;
  367                 u_int width;
  368                 int s;
  369                 char channel;
  370                 u_int ppr_options, period, offset;
  371                 uint16_t old_autoneg;
  372 
  373                 target_id = xm->xm_target;
  374                 our_id = chan->chan_id;
  375                 channel = 'A';
  376                 s = splbio();
  377                 tinfo = ahd_fetch_transinfo(ahd, channel, our_id, target_id,
  378                     &tstate);
  379                 ahd_compile_devinfo(&devinfo, our_id, target_id,
  380                     0, channel, ROLE_INITIATOR);
  381 
  382                 old_autoneg = tstate->auto_negotiate;
  383 
  384                 /*
  385                  * XXX since the period and offset are not provided here,
  386                  * fake things by forcing a renegotiation using the user
  387                  * settings if this is called for the first time (i.e.
  388                  * during probe). Also, cap various values at the user
  389                  * values, assuming that the user set it up that way.
  390                  */
  391                 if (ahd->inited_target[target_id] == 0) {
  392                         period = tinfo->user.period;
  393                         offset = tinfo->user.offset;
  394                         ppr_options = tinfo->user.ppr_options;
  395                         width = tinfo->user.width;
  396                         tstate->tagenable |=
  397                             (ahd->user_tagenable & devinfo.target_mask);
  398                         tstate->discenable |=
  399                             (ahd->user_discenable & devinfo.target_mask);
  400                         ahd->inited_target[target_id] = 1;
  401                         first = 1;
  402                 } else
  403                         first = 0;
  404 
  405                 if (xm->xm_mode & (PERIPH_CAP_WIDE16 | PERIPH_CAP_DT))
  406                         width = MSG_EXT_WDTR_BUS_16_BIT;
  407                 else
  408                         width = MSG_EXT_WDTR_BUS_8_BIT;
  409 
  410                 ahd_validate_width(ahd, NULL, &width, ROLE_UNKNOWN);
  411                 if (width > tinfo->user.width)
  412                         width = tinfo->user.width;
  413                 ahd_set_width(ahd, &devinfo, width, AHD_TRANS_GOAL, FALSE);
  414 
  415                 if (!(xm->xm_mode & (PERIPH_CAP_SYNC | PERIPH_CAP_DT))) {
  416                         period = 0;
  417                         offset = 0;
  418                         ppr_options = 0;
  419                 }
  420 
  421                 if ((xm->xm_mode & PERIPH_CAP_DT) &&
  422                     (tinfo->user.ppr_options & MSG_EXT_PPR_DT_REQ))
  423                         ppr_options |= MSG_EXT_PPR_DT_REQ;
  424                 else
  425                         ppr_options &= ~MSG_EXT_PPR_DT_REQ;
  426 
  427                 if ((tstate->discenable & devinfo.target_mask) == 0 ||
  428                     (tstate->tagenable & devinfo.target_mask) == 0)
  429                         ppr_options &= ~MSG_EXT_PPR_IU_REQ;
  430 
  431                 if ((xm->xm_mode & PERIPH_CAP_TQING) &&
  432                     (ahd->user_tagenable & devinfo.target_mask))
  433                         tstate->tagenable |= devinfo.target_mask;
  434                 else
  435                         tstate->tagenable &= ~devinfo.target_mask;
  436 
  437                 ahd_find_syncrate(ahd, &period, &ppr_options, AHD_SYNCRATE_MAX);
  438                 ahd_validate_offset(ahd, NULL, period, &offset,
  439                     MSG_EXT_WDTR_BUS_8_BIT, ROLE_UNKNOWN);
  440                 if (offset == 0) {
  441                         period = 0;
  442                         ppr_options = 0;
  443                 }
  444                 if (ppr_options != 0
  445                     && tinfo->user.transport_version >= 3) {
  446                         tinfo->goal.transport_version =
  447                             tinfo->user.transport_version;
  448                         tinfo->curr.transport_version =
  449                             tinfo->user.transport_version;
  450                 }
  451 
  452                 ahd_set_syncrate(ahd, &devinfo, period, offset,
  453                     ppr_options, AHD_TRANS_GOAL, FALSE);
  454 
  455                 /*
  456                  * If this is the first request, and no negotiation is
  457                  * needed, just confirm the state to the scsipi layer,
  458                  * so that it can print a message.
  459                  */
  460                 if (old_autoneg == tstate->auto_negotiate && first) {
  461                         xm->xm_mode = 0;
  462                         xm->xm_period = tinfo->curr.period;
  463                         xm->xm_offset = tinfo->curr.offset;
  464                         if (tinfo->curr.width == MSG_EXT_WDTR_BUS_16_BIT)
  465                                 xm->xm_mode |= PERIPH_CAP_WIDE16;
  466                         if (tinfo->curr.period)
  467                                 xm->xm_mode |= PERIPH_CAP_SYNC;
  468                         if (tstate->tagenable & devinfo.target_mask)
  469                                 xm->xm_mode |= PERIPH_CAP_TQING;
  470                         if (tinfo->curr.ppr_options & MSG_EXT_PPR_DT_REQ)
  471                                 xm->xm_mode |= PERIPH_CAP_DT;
  472                         scsipi_async_event(chan, ASYNC_EVENT_XFER_MODE, xm);
  473                 }
  474                 splx(s);
  475             }
  476         }
  477 
  478         return;
  479 }
  480 
  481 static void
  482 ahd_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments)
  483 {
  484         struct scb *scb;
  485         struct scsipi_xfer *xs;
  486         struct ahd_softc *ahd;
  487         struct ahd_initiator_tinfo *tinfo;
  488         struct ahd_tmode_tstate *tstate;
  489         u_int  mask;
  490         int    s;
  491 
  492         scb = (struct scb*)arg;
  493         xs = scb->xs;
  494         xs->error = 0;
  495         xs->status = 0;
  496         xs->xs_status = 0;
  497         ahd = (void*)xs->xs_periph->periph_channel->chan_adapter->adapt_dev;
  498 
  499         scb->sg_count = 0;
  500         if (nsegments != 0) {
  501                 void *sg;
  502                 int op;
  503                 u_int i;
  504 
  505                 ahd_setup_data_scb(ahd, scb);
  506 
  507                 /* Copy the segments into our SG list */
  508                 for (i = nsegments, sg = scb->sg_list; i > 0; i--) {
  509 
  510                         sg = ahd_sg_setup(ahd, scb, sg, dm_segs->ds_addr,
  511                                           dm_segs->ds_len,
  512                                           /*last*/i == 1);
  513                         dm_segs++;
  514                 }
  515 
  516                 if (xs->xs_control & XS_CTL_DATA_IN)
  517                         op = BUS_DMASYNC_PREREAD;
  518                 else
  519                         op = BUS_DMASYNC_PREWRITE;
  520 
  521                 bus_dmamap_sync(ahd->parent_dmat, scb->dmamap, 0,
  522                                 scb->dmamap->dm_mapsize, op);
  523         }
  524 
  525         ahd_lock(ahd, &s);
  526 
  527         /*
  528          * Last time we need to check if this SCB needs to
  529          * be aborted.
  530          */
  531         if (ahd_get_scsi_status(scb) == XS_STS_DONE) {
  532                 if (nsegments != 0)
  533                         bus_dmamap_unload(ahd->parent_dmat,
  534                                           scb->dmamap);
  535                 ahd_free_scb(ahd, scb);
  536                 ahd_unlock(ahd, &s);
  537                 return;
  538         }
  539 
  540         tinfo = ahd_fetch_transinfo(ahd, SCSIID_CHANNEL(ahd, scb->hscb->scsiid),
  541                                     SCSIID_OUR_ID(scb->hscb->scsiid),
  542                                     SCSIID_TARGET(ahd, scb->hscb->scsiid),
  543                                     &tstate);
  544 
  545         mask = SCB_GET_TARGET_MASK(ahd, scb);
  546 
  547         if ((tstate->discenable & mask) != 0)
  548                 scb->hscb->control |= DISCENB;
  549 
  550         if ((tstate->tagenable & mask) != 0)
  551                 scb->hscb->control |= xs->xs_tag_type|TAG_ENB;
  552 
  553         if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU) != 0) {
  554                 scb->flags |= SCB_PACKETIZED;
  555                 if (scb->hscb->task_management != 0)
  556                         scb->hscb->control &= ~MK_MESSAGE;
  557         }
  558 
  559 #if 0   /* This looks like it makes sense at first, but it can loop */
  560         if ((xs->xs_control & XS_CTL_DISCOVERY) &&
  561             (tinfo->goal.width != 0
  562              || tinfo->goal.period != 0
  563              || tinfo->goal.ppr_options != 0)) {
  564                 scb->flags |= SCB_NEGOTIATE;
  565                 scb->hscb->control |= MK_MESSAGE;
  566         } else
  567 #endif
  568         if ((tstate->auto_negotiate & mask) != 0) {
  569                 scb->flags |= SCB_AUTO_NEGOTIATE;
  570                 scb->hscb->control |= MK_MESSAGE;
  571         }
  572 
  573         LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links);
  574 
  575         scb->flags |= SCB_ACTIVE;
  576 
  577         if (!(xs->xs_control & XS_CTL_POLL)) {
  578                 callout_reset(&scb->xs->xs_callout, xs->timeout > 1000000 ?
  579                               (xs->timeout / 1000) * hz : (xs->timeout * hz) / 1000,
  580                               ahd_timeout, scb);
  581         }
  582 
  583         if ((scb->flags & SCB_TARGET_IMMEDIATE) != 0) {
  584                 /* Define a mapping from our tag to the SCB. */
  585                 ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb;
  586                 ahd_pause(ahd);
  587                 ahd_set_scbptr(ahd, SCB_GET_TAG(scb));
  588                 ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_TARG);
  589                 ahd_unpause(ahd);
  590         } else {
  591                 ahd_queue_scb(ahd, scb);
  592         }
  593 
  594         if (!(xs->xs_control & XS_CTL_POLL)) {
  595                 ahd_unlock(ahd, &s);
  596                 return;
  597         }
  598         /*
  599          * If we can't use interrupts, poll for completion
  600          */
  601         SC_DEBUG(xs->xs_periph, SCSIPI_DB3, ("cmd_poll\n"));
  602         do {
  603                 if (ahd_poll(ahd, xs->timeout)) {
  604                         if (!(xs->xs_control & XS_CTL_SILENT))
  605                                 printf("cmd fail\n");
  606                         ahd_timeout(scb);
  607                         break;
  608                 }
  609         } while (!(xs->xs_status & XS_STS_DONE));
  610 
  611         ahd_unlock(ahd, &s);
  612 }
  613 
  614 static int
  615 ahd_poll(struct ahd_softc *ahd, int wait)
  616 {
  617 
  618         while (--wait) {
  619                 DELAY(1000);
  620                 if (ahd_inb(ahd, INTSTAT) & INT_PEND)
  621                         break;
  622         }
  623 
  624         if (wait == 0) {
  625                 printf("%s: board is not responding\n", ahd_name(ahd));
  626                 return (EIO);
  627         }
  628 
  629         ahd_intr((void *)ahd);
  630         return (0);
  631 }
  632 
  633 
  634 static void
  635 ahd_setup_data(struct ahd_softc *ahd, struct scsipi_xfer *xs,
  636                struct scb *scb)
  637 {
  638         struct hardware_scb *hscb;
  639 
  640         hscb = scb->hscb;
  641         xs->resid = xs->status = 0;
  642 
  643         hscb->cdb_len = xs->cmdlen;
  644         if (hscb->cdb_len > MAX_CDB_LEN) {
  645                 int s;
  646                 /*
  647                  * Should CAM start to support CDB sizes
  648                  * greater than 16 bytes, we could use
  649                  * the sense buffer to store the CDB.
  650                  */
  651                 ahd_set_transaction_status(scb,
  652                                            XS_DRIVER_STUFFUP);
  653 
  654                 ahd_lock(ahd, &s);
  655                 ahd_free_scb(ahd, scb);
  656                 ahd_unlock(ahd, &s);
  657                 scsipi_done(xs);
  658         }
  659         memcpy(hscb->shared_data.idata.cdb, xs->cmd, hscb->cdb_len);
  660 
  661         /* Only use S/G if there is a transfer */
  662         if (xs->datalen) {
  663                 int error;
  664 
  665                 error = bus_dmamap_load(ahd->parent_dmat,
  666                                         scb->dmamap, xs->data,
  667                                         xs->datalen, NULL,
  668                                         ((xs->xs_control & XS_CTL_NOSLEEP) ?
  669                                          BUS_DMA_NOWAIT : BUS_DMA_WAITOK) |
  670                                         BUS_DMA_STREAMING |
  671                                         ((xs->xs_control & XS_CTL_DATA_IN) ?
  672                                          BUS_DMA_READ : BUS_DMA_WRITE));
  673                 if (error) {
  674 #ifdef AHD_DEBUG
  675                         printf("%s: in ahc_setup_data(): bus_dmamap_load() "
  676                                "= %d\n",
  677                                ahd_name(ahd), error);
  678 #endif
  679                         xs->error = XS_RESOURCE_SHORTAGE;
  680                         scsipi_done(xs);
  681                         return;
  682                 }
  683                 ahd_execute_scb(scb,
  684                                 scb->dmamap->dm_segs,
  685                                 scb->dmamap->dm_nsegs);
  686         } else {
  687                 ahd_execute_scb(scb, NULL, 0);
  688         }
  689 }
  690 
  691 void
  692 ahd_timeout(void *arg)
  693 {
  694         struct  scb       *scb;
  695         struct  ahd_softc *ahd;
  696         ahd_mode_state     saved_modes;
  697         int                s;
  698 
  699         scb = (struct scb *)arg;
  700         ahd = (struct ahd_softc *)scb->ahd_softc;
  701 
  702         printf("%s: ahd_timeout\n", ahd_name(ahd));
  703 
  704         ahd_lock(ahd, &s);
  705 
  706         ahd_pause_and_flushwork(ahd);
  707         saved_modes = ahd_save_modes(ahd);
  708 #if 0
  709         ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
  710         ahd_outb(ahd, SCSISIGO, ACKO);
  711         printf("set ACK\n");
  712         ahd_outb(ahd, SCSISIGO, 0);
  713         printf("clearing Ack\n");
  714         ahd_restore_modes(ahd, saved_modes);
  715 #endif
  716         if ((scb->flags & SCB_ACTIVE) == 0) {
  717                 /* Previous timeout took care of me already */
  718                 printf("%s: Timedout SCB already complete. "
  719                        "Interrupts may not be functioning.\n", ahd_name(ahd));
  720                 ahd_unpause(ahd);
  721                 ahd_unlock(ahd, &s);
  722                 return;
  723         }
  724 
  725         ahd_print_path(ahd, scb);
  726         printf("SCB 0x%x - timed out\n", SCB_GET_TAG(scb));
  727         ahd_dump_card_state(ahd);
  728         ahd_reset_channel(ahd, SIM_CHANNEL(ahd, sim),
  729                           /*initiate reset*/TRUE);
  730         ahd_unlock(ahd, &s);
  731         return;
  732 }
  733 
  734 int
  735 ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg)
  736 {
  737         ahd->platform_data = malloc(sizeof(struct ahd_platform_data), M_DEVBUF,
  738                                     M_NOWAIT /*| M_ZERO*/);
  739         if (ahd->platform_data == NULL)
  740                 return (ENOMEM);
  741 
  742         memset(ahd->platform_data, 0, sizeof(struct ahd_platform_data));
  743 
  744         return (0);
  745 }
  746 
  747 void
  748 ahd_platform_free(struct ahd_softc *ahd)
  749 {
  750         free(ahd->platform_data, M_DEVBUF);
  751 }
  752 
  753 int
  754 ahd_softc_comp(struct ahd_softc *lahd, struct ahd_softc *rahd)
  755 {
  756         /* We don't sort softcs under NetBSD so report equal always */
  757         return (0);
  758 }
  759 
  760 int
  761 ahd_detach(struct device *self, int flags)
  762 {
  763         int rv = 0;
  764 
  765         struct ahd_softc *ahd = (struct ahd_softc*)self;
  766 
  767         if (ahd->sc_child != NULL)
  768                 rv = config_detach((void *)ahd->sc_child, flags);
  769 
  770         shutdownhook_disestablish(ahd->shutdown_hook);
  771 
  772         ahd_free(ahd);
  773 
  774         return rv;
  775 }
  776 
  777 void
  778 ahd_platform_set_tags(struct ahd_softc *ahd,
  779                       struct ahd_devinfo *devinfo, ahd_queue_alg alg)
  780 {
  781         struct ahd_tmode_tstate *tstate;
  782 
  783         ahd_fetch_transinfo(ahd, devinfo->channel, devinfo->our_scsiid,
  784                             devinfo->target, &tstate);
  785 
  786         if (alg != AHD_QUEUE_NONE)
  787                 tstate->tagenable |= devinfo->target_mask;
  788         else
  789                 tstate->tagenable &= ~devinfo->target_mask;
  790 }
  791 
  792 void
  793 ahd_send_async(struct ahd_softc *ahc, char channel, u_int target, u_int lun,
  794                ac_code code, void *opt_arg)
  795 {
  796         struct ahd_tmode_tstate *tstate;
  797         struct ahd_initiator_tinfo *tinfo;
  798         struct ahd_devinfo devinfo;
  799         struct scsipi_channel *chan;
  800         struct scsipi_xfer_mode xm;
  801 
  802 #ifdef DIAGNOSTIC
  803         if (channel != 'A')
  804                 panic("ahd_send_async: not channel A");
  805 #endif
  806         chan = &ahc->sc_channel;
  807         switch (code) {
  808         case AC_TRANSFER_NEG:
  809                 tinfo = ahd_fetch_transinfo(ahc, channel, ahc->our_id, target,
  810                             &tstate);
  811                 ahd_compile_devinfo(&devinfo, ahc->our_id, target, lun,
  812                     channel, ROLE_UNKNOWN);
  813                 /*
  814                  * Don't bother if negotiating. XXX?
  815                  */
  816                 if (tinfo->curr.period != tinfo->goal.period
  817                     || tinfo->curr.width != tinfo->goal.width
  818                     || tinfo->curr.offset != tinfo->goal.offset
  819                     || tinfo->curr.ppr_options != tinfo->goal.ppr_options)
  820                         break;
  821                 xm.xm_target = target;
  822                 xm.xm_mode = 0;
  823                 xm.xm_period = tinfo->curr.period;
  824                 xm.xm_offset = tinfo->curr.offset;
  825                 if (tinfo->goal.ppr_options & MSG_EXT_PPR_DT_REQ)
  826                         xm.xm_mode |= PERIPH_CAP_DT;
  827                 if (tinfo->curr.width == MSG_EXT_WDTR_BUS_16_BIT)
  828                         xm.xm_mode |= PERIPH_CAP_WIDE16;
  829                 if (tinfo->curr.period)
  830                         xm.xm_mode |= PERIPH_CAP_SYNC;
  831                 if (tstate->tagenable & devinfo.target_mask)
  832                         xm.xm_mode |= PERIPH_CAP_TQING;
  833                 scsipi_async_event(chan, ASYNC_EVENT_XFER_MODE, &xm);
  834                 break;
  835         case AC_BUS_RESET:
  836                 scsipi_async_event(chan, ASYNC_EVENT_RESET, NULL);
  837         case AC_SENT_BDR:
  838         default:
  839                 break;
  840         }
  841 }

Cache object: 56038e5a5a3f886f9747e0366e14d300


[ 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.