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/aic/aic.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 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 1999 Luoqi Chen.
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 #include <sys/param.h>
   33 #include <sys/conf.h>
   34 #include <sys/systm.h>
   35 #include <sys/kernel.h>
   36 #include <sys/lock.h>
   37 #include <sys/mutex.h>
   38 #include <sys/malloc.h>
   39 #include <sys/bus.h>
   40 
   41 #include <machine/bus.h>
   42 #include <sys/rman.h>
   43 
   44 #include <cam/cam.h>
   45 #include <cam/cam_ccb.h>
   46 #include <cam/cam_sim.h>
   47 #include <cam/cam_xpt_sim.h>
   48 #include <cam/cam_debug.h>
   49 
   50 #include <cam/scsi/scsi_message.h>
   51 
   52 #include <dev/aic/aic6360reg.h>
   53 #include <dev/aic/aicvar.h>
   54 
   55 static void aic_action(struct cam_sim *sim, union ccb *ccb);
   56 static void aic_execute_scb(void *arg, bus_dma_segment_t *dm_segs,
   57                                 int nseg, int error);
   58 static void aic_intr_locked(struct aic_softc *aic);
   59 static void aic_start(struct aic_softc *aic);
   60 static void aic_select(struct aic_softc *aic);
   61 static void aic_selected(struct aic_softc *aic);
   62 static void aic_reselected(struct aic_softc *aic);
   63 static void aic_reconnect(struct aic_softc *aic, int tag);
   64 static void aic_cmd(struct aic_softc *aic);
   65 static void aic_msgin(struct aic_softc *aic);
   66 static void aic_handle_msgin(struct aic_softc *aic);
   67 static void aic_msgout(struct aic_softc *aic);
   68 static void aic_datain(struct aic_softc *aic);
   69 static void aic_dataout(struct aic_softc *aic);
   70 static void aic_done(struct aic_softc *aic, struct aic_scb *scb);
   71 static void aic_poll(struct cam_sim *sim);
   72 static void aic_timeout(void *arg);
   73 static void aic_scsi_reset(struct aic_softc *aic);
   74 static void aic_chip_reset(struct aic_softc *aic);
   75 static void aic_reset(struct aic_softc *aic, int initiate_reset);
   76 
   77 devclass_t aic_devclass;
   78 
   79 static struct aic_scb *
   80 aic_get_scb(struct aic_softc *aic)
   81 {
   82         struct aic_scb *scb;
   83 
   84         if (!dumping)
   85                 mtx_assert(&aic->lock, MA_OWNED);
   86         if ((scb = SLIST_FIRST(&aic->free_scbs)) != NULL)
   87                 SLIST_REMOVE_HEAD(&aic->free_scbs, link);
   88         return (scb);
   89 }
   90 
   91 static void
   92 aic_free_scb(struct aic_softc *aic, struct aic_scb *scb)
   93 {
   94 
   95         if (!dumping)
   96                 mtx_assert(&aic->lock, MA_OWNED);
   97         if ((aic->flags & AIC_RESOURCE_SHORTAGE) != 0 &&
   98             (scb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) {
   99                 scb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
  100                 aic->flags &= ~AIC_RESOURCE_SHORTAGE;
  101         }
  102         scb->flags = 0;
  103         SLIST_INSERT_HEAD(&aic->free_scbs, scb, link);
  104 }
  105 
  106 static void
  107 aic_action(struct cam_sim *sim, union ccb *ccb)
  108 {
  109         struct aic_softc *aic;
  110 
  111         CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("aic_action\n"));
  112 
  113         aic = (struct aic_softc *)cam_sim_softc(sim);
  114         mtx_assert(&aic->lock, MA_OWNED);
  115 
  116         switch (ccb->ccb_h.func_code) {
  117         case XPT_SCSI_IO:       /* Execute the requested I/O operation */
  118         case XPT_RESET_DEV:     /* Bus Device Reset the specified SCSI device */
  119         {               
  120                 struct aic_scb *scb;
  121 
  122                 if ((scb = aic_get_scb(aic)) == NULL) {
  123                         aic->flags |= AIC_RESOURCE_SHORTAGE;
  124                         xpt_freeze_simq(aic->sim, /*count*/1);
  125                         ccb->ccb_h.status = CAM_REQUEUE_REQ;
  126                         xpt_done(ccb);
  127                         return;
  128                 }
  129 
  130                 scb->ccb = ccb;
  131                 ccb->ccb_h.ccb_scb_ptr = scb;
  132                 ccb->ccb_h.ccb_aic_ptr = aic;
  133 
  134                 scb->target = ccb->ccb_h.target_id;
  135                 scb->lun = ccb->ccb_h.target_lun;
  136 
  137                 if (ccb->ccb_h.func_code == XPT_SCSI_IO) {
  138                         scb->cmd_len = ccb->csio.cdb_len;
  139                         if (ccb->ccb_h.flags & CAM_CDB_POINTER) {
  140                                 if (ccb->ccb_h.flags & CAM_CDB_PHYS) {
  141                                         ccb->ccb_h.status = CAM_REQ_INVALID;
  142                                         aic_free_scb(aic, scb);
  143                                         xpt_done(ccb);
  144                                         return;
  145                                 }
  146                                 scb->cmd_ptr = ccb->csio.cdb_io.cdb_ptr;
  147                         } else {
  148                                 scb->cmd_ptr = ccb->csio.cdb_io.cdb_bytes;
  149                         }
  150                         if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
  151                                 if ((ccb->ccb_h.flags & CAM_DATA_MASK) !=
  152                                     CAM_DATA_VADDR) {
  153                                         ccb->ccb_h.status = CAM_REQ_INVALID;
  154                                         aic_free_scb(aic, scb);
  155                                         xpt_done(ccb);
  156                                         return;
  157                                 }
  158                                 scb->data_ptr = ccb->csio.data_ptr;
  159                                 scb->data_len = ccb->csio.dxfer_len;
  160                         } else {
  161                                 scb->data_ptr = NULL;
  162                                 scb->data_len = 0;
  163                         }
  164                         aic_execute_scb(scb, NULL, 0, 0);
  165                 } else {
  166                         scb->flags |= SCB_DEVICE_RESET;
  167                         aic_execute_scb(scb, NULL, 0, 0);
  168                 }
  169                 break;
  170         }
  171         case XPT_SET_TRAN_SETTINGS:
  172         {
  173                 struct ccb_trans_settings *cts = &ccb->cts;
  174                 struct aic_tinfo *ti = &aic->tinfo[ccb->ccb_h.target_id];
  175                 struct ccb_trans_settings_scsi *scsi =
  176                     &cts->proto_specific.scsi;
  177                 struct ccb_trans_settings_spi *spi =
  178                     &cts->xport_specific.spi;
  179 
  180                 if ((spi->valid & CTS_SPI_VALID_DISC) != 0 &&
  181                     (aic->flags & AIC_DISC_ENABLE) != 0) {
  182                         if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0)
  183                                 ti->flags |= TINFO_DISC_ENB;
  184                         else
  185                                 ti->flags &= ~TINFO_DISC_ENB;
  186                 }
  187 
  188                 if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
  189                         if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0)
  190                                 ti->flags |= TINFO_TAG_ENB;
  191                         else
  192                                 ti->flags &= ~TINFO_TAG_ENB;
  193                 }
  194 
  195                 if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) {
  196                         ti->goal.period = spi->sync_period;
  197 
  198                         if (ti->goal.period > aic->min_period) {
  199                                 ti->goal.period = 0;
  200                                 ti->goal.offset = 0;
  201                         } else if (ti->goal.period < aic->max_period)
  202                                 ti->goal.period = aic->max_period;
  203                 }
  204 
  205                 if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0) {
  206                         ti->goal.offset = spi->sync_offset;
  207                         if (ti->goal.offset == 0)
  208                                 ti->goal.period = 0;
  209                         else if (ti->goal.offset > AIC_SYNC_OFFSET)
  210                                 ti->goal.offset = AIC_SYNC_OFFSET;
  211                 }
  212 
  213                 if ((ti->goal.period != ti->current.period)
  214                  || (ti->goal.offset != ti->current.offset))
  215                         ti->flags |= TINFO_SDTR_NEGO;
  216 
  217                 ccb->ccb_h.status = CAM_REQ_CMP;
  218                 xpt_done(ccb);
  219                 break;
  220         }
  221         case XPT_GET_TRAN_SETTINGS:
  222         {
  223                 struct ccb_trans_settings *cts = &ccb->cts;
  224                 struct aic_tinfo *ti = &aic->tinfo[ccb->ccb_h.target_id];
  225                 struct ccb_trans_settings_scsi *scsi =
  226                     &cts->proto_specific.scsi;
  227                 struct ccb_trans_settings_spi *spi =
  228                     &cts->xport_specific.spi;
  229 
  230                 cts->protocol = PROTO_SCSI;
  231                 cts->protocol_version = SCSI_REV_2;
  232                 cts->transport = XPORT_SPI;
  233                 cts->transport_version = 2;
  234                 scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
  235                 spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
  236 
  237                 if ((ti->flags & TINFO_DISC_ENB) != 0)
  238                         spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
  239                 if ((ti->flags & TINFO_TAG_ENB) != 0)
  240                         scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
  241 
  242                 if (cts->type == CTS_TYPE_CURRENT_SETTINGS) {
  243                         spi->sync_period = ti->current.period;
  244                         spi->sync_offset = ti->current.offset;
  245                 } else {
  246                         spi->sync_period = ti->user.period;
  247                         spi->sync_offset = ti->user.offset;
  248                 }
  249 
  250                 spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
  251                 spi->valid = CTS_SPI_VALID_SYNC_RATE
  252                            | CTS_SPI_VALID_SYNC_OFFSET
  253                            | CTS_SPI_VALID_BUS_WIDTH
  254                            | CTS_SPI_VALID_DISC;
  255                 scsi->valid = CTS_SCSI_VALID_TQ;
  256 
  257                 ccb->ccb_h.status = CAM_REQ_CMP;
  258                 xpt_done(ccb);
  259                 break;
  260         }
  261         case XPT_CALC_GEOMETRY:
  262         {
  263                 cam_calc_geometry(&ccb->ccg, /*extended*/1);
  264                 xpt_done(ccb);
  265                 break;
  266         }
  267         case XPT_RESET_BUS:             /* Reset the specified SCSI bus */
  268                 aic_reset(aic, /*initiate_reset*/TRUE);
  269                 ccb->ccb_h.status = CAM_REQ_CMP;
  270                 xpt_done(ccb);
  271                 break;
  272         case XPT_PATH_INQ:              /* Path routing inquiry */
  273         {       
  274                 struct ccb_pathinq *cpi = &ccb->cpi;
  275 
  276                 cpi->version_num = 1; /* XXX??? */
  277                 cpi->hba_inquiry = PI_SDTR_ABLE | PI_TAG_ABLE;
  278                 cpi->target_sprt = 0;
  279                 cpi->hba_misc = 0;
  280                 cpi->hba_eng_cnt = 0;
  281                 cpi->max_target = 7;
  282                 cpi->max_lun = 7;
  283                 cpi->initiator_id = aic->initiator;
  284                 cpi->bus_id = cam_sim_bus(sim);
  285                 cpi->base_transfer_speed = 3300;
  286                 strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
  287                 strlcpy(cpi->hba_vid, "Adaptec", HBA_IDLEN);
  288                 strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
  289                 cpi->unit_number = cam_sim_unit(sim);
  290                 cpi->transport = XPORT_SPI;
  291                 cpi->transport_version = 2;
  292                 cpi->protocol = PROTO_SCSI;
  293                 cpi->protocol_version = SCSI_REV_2;
  294                 cpi->ccb_h.status = CAM_REQ_CMP;
  295                 xpt_done(ccb);
  296                 break;
  297         }
  298         default:
  299                 ccb->ccb_h.status = CAM_REQ_INVALID;
  300                 xpt_done(ccb);
  301                 break;
  302         }
  303 }
  304 
  305 static void
  306 aic_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
  307 {
  308         struct aic_scb *scb = (struct aic_scb *)arg;
  309         union ccb *ccb = scb->ccb;
  310         struct aic_softc *aic = (struct aic_softc *)ccb->ccb_h.ccb_aic_ptr;
  311 
  312         if (!dumping)
  313                 mtx_assert(&aic->lock, MA_OWNED);
  314         if (ccb->ccb_h.status != CAM_REQ_INPROG) {
  315                 aic_free_scb(aic, scb);
  316                 xpt_done(ccb);
  317                 return;
  318         }
  319 
  320         scb->flags |= SCB_ACTIVE;
  321         ccb->ccb_h.status |= CAM_SIM_QUEUED;
  322         TAILQ_INSERT_TAIL(&aic->pending_ccbs, &ccb->ccb_h, sim_links.tqe);
  323 
  324         callout_reset_sbt(&scb->timer, SBT_1MS * ccb->ccb_h.timeout, 0,
  325             aic_timeout, scb, 0);
  326 
  327         aic_start(aic);
  328 }
  329 
  330 /*
  331  * Start another command if the controller is not busy.
  332  */
  333 static void
  334 aic_start(struct aic_softc *aic)
  335 {
  336         struct ccb_hdr *ccb_h;
  337         struct aic_tinfo *ti;
  338 
  339         if (aic->state != AIC_IDLE)
  340                 return;
  341 
  342         TAILQ_FOREACH(ccb_h, &aic->pending_ccbs, sim_links.tqe) {
  343                 ti = &aic->tinfo[ccb_h->target_id];
  344                 if ((ti->lubusy & (1 << ccb_h->target_lun)) == 0) {
  345                         TAILQ_REMOVE(&aic->pending_ccbs, ccb_h, sim_links.tqe);
  346                         aic->nexus = (struct aic_scb *)ccb_h->ccb_scb_ptr;
  347                         aic_select(aic);
  348                         return;
  349                 }
  350         }
  351 
  352         CAM_DEBUG_PRINT(CAM_DEBUG_TRACE, ("aic_start: idle\n"));
  353 
  354         aic_outb(aic, SIMODE0, ENSELDI);
  355         aic_outb(aic, SIMODE1, ENSCSIRST);
  356         aic_outb(aic, SCSISEQ, ENRESELI);
  357 }
  358 
  359 /*
  360  * Start a selection.
  361  */
  362 static void
  363 aic_select(struct aic_softc *aic)
  364 {
  365         struct aic_scb *scb = aic->nexus;
  366 
  367         CAM_DEBUG(scb->ccb->ccb_h.path, CAM_DEBUG_TRACE,
  368                   ("aic_select - ccb %p\n", scb->ccb));
  369 
  370         aic->state = AIC_SELECTING;
  371 
  372         aic_outb(aic, DMACNTRL1, 0);
  373         aic_outb(aic, SCSIID, aic->initiator << OID_S | scb->target);
  374         aic_outb(aic, SXFRCTL1, STIMO_256ms | ENSTIMER |
  375             (aic->flags & AIC_PARITY_ENABLE ? ENSPCHK : 0));
  376 
  377         aic_outb(aic, SIMODE0, ENSELDI|ENSELDO);
  378         aic_outb(aic, SIMODE1, ENSCSIRST|ENSELTIMO);
  379         aic_outb(aic, SCSISEQ, ENRESELI|ENSELO|ENAUTOATNO);
  380 }
  381 
  382 /*
  383  * We have successfully selected a target, prepare for the information
  384  * transfer phases.
  385  */
  386 static void
  387 aic_selected(struct aic_softc *aic)
  388 {
  389         struct aic_scb *scb = aic->nexus;
  390         union ccb *ccb = scb->ccb;
  391         struct aic_tinfo *ti = &aic->tinfo[scb->target];
  392 
  393         CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
  394                   ("aic_selected - ccb %p\n", ccb));
  395 
  396         aic->state = AIC_HASNEXUS;
  397 
  398         if (scb->flags & SCB_DEVICE_RESET) {
  399                 aic->msg_buf[0] = MSG_BUS_DEV_RESET;
  400                 aic->msg_len = 1;
  401                 aic->msg_outq = AIC_MSG_MSGBUF;
  402         } else {
  403                 aic->msg_outq = AIC_MSG_IDENTIFY;
  404                 if ((ti->flags & TINFO_TAG_ENB) != 0 &&
  405                     (ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0)
  406                         aic->msg_outq |= AIC_MSG_TAG_Q;
  407                 else
  408                         ti->lubusy |= 1 << scb->lun;
  409                 if ((ti->flags & TINFO_SDTR_NEGO) != 0)
  410                         aic->msg_outq |= AIC_MSG_SDTR;
  411         }
  412 
  413         aic_outb(aic, CLRSINT0, CLRSELDO);
  414         aic_outb(aic, CLRSINT1, CLRBUSFREE);
  415         aic_outb(aic, SCSISEQ, ENAUTOATNP);
  416         aic_outb(aic, SIMODE0, 0);
  417         aic_outb(aic, SIMODE1, ENSCSIRST|ENBUSFREE|ENREQINIT);
  418         aic_outb(aic, SCSIRATE, ti->scsirate);
  419 }
  420 
  421 /*
  422  * We are re-selected by a target, save the target id and wait for the
  423  * target to further identify itself.
  424  */
  425 static void
  426 aic_reselected(struct aic_softc *aic)
  427 {
  428         u_int8_t selid;
  429 
  430         CAM_DEBUG_PRINT(CAM_DEBUG_TRACE, ("aic_reselected\n"));
  431 
  432         /*
  433          * If we have started a selection, it must have lost out in
  434          * the arbitration, put the command back to the pending queue.
  435          */
  436         if (aic->nexus) {
  437                 TAILQ_INSERT_HEAD(&aic->pending_ccbs,
  438                     &aic->nexus->ccb->ccb_h, sim_links.tqe);
  439                 aic->nexus = NULL;
  440         }
  441 
  442         selid = aic_inb(aic, SELID) & ~(1 << aic->initiator);
  443         if (selid & (selid - 1)) {
  444                 /* this should never have happened */
  445                 printf("aic_reselected: invalid selid %x\n", selid);
  446                 aic_reset(aic, /*initiate_reset*/TRUE);
  447                 return;
  448         }
  449 
  450         aic->state = AIC_RESELECTED;
  451         aic->target = ffs(selid) - 1;
  452         aic->lun = -1;
  453 
  454         aic_outb(aic, CLRSINT0, CLRSELDI);
  455         aic_outb(aic, CLRSINT1, CLRBUSFREE);
  456         aic_outb(aic, SIMODE0, 0);
  457         aic_outb(aic, SIMODE1, ENSCSIRST|ENBUSFREE|ENREQINIT);
  458         aic_outb(aic, SCSISEQ, ENAUTOATNP);
  459         aic_outb(aic, SCSIRATE, aic->tinfo[aic->target].scsirate);
  460 }
  461 
  462 /*
  463  * Raise ATNO to signal the target that we have a message for it.
  464  */
  465 static __inline void
  466 aic_sched_msgout(struct aic_softc *aic, u_int8_t msg)
  467 {
  468         if (msg) {
  469                 aic->msg_buf[0] = msg;
  470                 aic->msg_len = 1;
  471         }
  472         aic->msg_outq |= AIC_MSG_MSGBUF;
  473         aic_outb(aic, SCSISIGO, aic_inb(aic, SCSISIGI) | ATNO);
  474 }
  475 
  476 /*
  477  * Wait for SPIORDY (SCSI PIO ready) flag, or a phase change.
  478  */
  479 static __inline int
  480 aic_spiordy(struct aic_softc *aic)
  481 {
  482         while (!(aic_inb(aic, DMASTAT) & INTSTAT) &&
  483             !(aic_inb(aic, SSTAT0) & SPIORDY))
  484                 ;
  485         return !(aic_inb(aic, DMASTAT) & INTSTAT);
  486 }
  487 
  488 /*
  489  * Reestablish a disconnected nexus.
  490  */
  491 static void
  492 aic_reconnect(struct aic_softc *aic, int tag)
  493 {
  494         struct aic_scb *scb;
  495         struct ccb_hdr *ccb_h;
  496 
  497         CAM_DEBUG_PRINT(CAM_DEBUG_TRACE, ("aic_reconnect\n"));
  498 
  499         /* Find the nexus */
  500         scb = NULL;
  501         TAILQ_FOREACH(ccb_h, &aic->nexus_ccbs, sim_links.tqe) {
  502                 scb = (struct aic_scb *)ccb_h->ccb_scb_ptr;
  503                 if (scb->target == aic->target && scb->lun == aic->lun &&
  504                     (tag == -1 || scb->tag == tag))
  505                         break;
  506         }
  507 
  508         /* ABORT if nothing is found */
  509         if (!ccb_h) {
  510                 if (tag == -1)
  511                         aic_sched_msgout(aic, MSG_ABORT);
  512                 else
  513                         aic_sched_msgout(aic, MSG_ABORT_TAG);
  514                 xpt_async(AC_UNSOL_RESEL, aic->path, NULL);
  515                 return;
  516         }
  517 
  518         /* Reestablish the nexus */
  519         TAILQ_REMOVE(&aic->nexus_ccbs, ccb_h, sim_links.tqe);
  520         aic->nexus = scb;
  521         scb->flags &= ~SCB_DISCONNECTED;
  522         aic->state = AIC_HASNEXUS;
  523 }
  524 
  525 /*
  526  * Read messages.
  527  */
  528 static void
  529 aic_msgin(struct aic_softc *aic)
  530 {
  531         int msglen;
  532 
  533         CAM_DEBUG_PRINT(CAM_DEBUG_TRACE, ("aic_msgin\n"));
  534 
  535         aic_outb(aic, SIMODE1, ENSCSIRST|ENPHASEMIS|ENBUSFREE);
  536         aic_outb(aic, SXFRCTL0, CHEN|SPIOEN);
  537 
  538         aic->flags &= ~AIC_DROP_MSGIN;
  539         aic->msg_len = 0;
  540         do {
  541                 /*
  542                  * If a parity error is detected, drop the remaining
  543                  * bytes and inform the target so it could resend
  544                  * the messages.
  545                  */
  546                 if (aic_inb(aic, SSTAT1) & SCSIPERR) {
  547                         aic_outb(aic, CLRSINT1, CLRSCSIPERR);
  548                         aic->flags |= AIC_DROP_MSGIN;
  549                         aic_sched_msgout(aic, MSG_PARITY_ERROR);
  550                 }
  551                 if ((aic->flags & AIC_DROP_MSGIN)) {
  552                         aic_inb(aic, SCSIDAT);
  553                         continue;
  554                 }
  555                 /* read the message byte without ACKing on it */
  556                 aic->msg_buf[aic->msg_len++] = aic_inb(aic, SCSIBUS);
  557                 if (aic->msg_buf[0] == MSG_EXTENDED) {
  558                         if (aic->msg_len < 2) {
  559                                 (void) aic_inb(aic, SCSIDAT);
  560                                 continue;
  561                         }
  562                         switch (aic->msg_buf[2]) {
  563                         case MSG_EXT_SDTR:
  564                                 msglen = MSG_EXT_SDTR_LEN;
  565                                 break;
  566                         case MSG_EXT_WDTR:
  567                                 msglen = MSG_EXT_WDTR_LEN;
  568                                 break;
  569                         default:
  570                                 msglen = 0;
  571                                 break;
  572                         }
  573                         if (aic->msg_buf[1] != msglen) {
  574                                 aic->flags |= AIC_DROP_MSGIN;
  575                                 aic_sched_msgout(aic, MSG_MESSAGE_REJECT);
  576                         }
  577                         msglen += 2;
  578                 } else if (aic->msg_buf[0] >= 0x20 && aic->msg_buf[0] <= 0x2f)
  579                         msglen = 2;
  580                 else
  581                         msglen = 1;
  582                 /*
  583                  * If we have a complete message, handle it before the final
  584                  * ACK (in case we decide to reject the message).
  585                  */
  586                 if (aic->msg_len == msglen) {
  587                         aic_handle_msgin(aic);
  588                         aic->msg_len = 0;
  589                 }
  590                 /* ACK on the message byte */
  591                 (void) aic_inb(aic, SCSIDAT);
  592         } while (aic_spiordy(aic));
  593 
  594         aic_outb(aic, SXFRCTL0, CHEN);
  595         aic_outb(aic, SIMODE1, ENSCSIRST|ENBUSFREE|ENREQINIT);
  596 }
  597 
  598 /*
  599  * Handle a message.
  600  */
  601 static void
  602 aic_handle_msgin(struct aic_softc *aic)
  603 {
  604         struct aic_scb *scb;
  605         struct ccb_hdr *ccb_h;
  606         struct aic_tinfo *ti;
  607         struct ccb_trans_settings neg;
  608         struct ccb_trans_settings_spi *spi = &neg.xport_specific.spi;
  609 
  610         if (aic->state == AIC_RESELECTED) {
  611                 if (!MSG_ISIDENTIFY(aic->msg_buf[0])) {
  612                         aic_sched_msgout(aic, MSG_MESSAGE_REJECT);
  613                         return;
  614                 }
  615                 aic->lun = aic->msg_buf[0] & MSG_IDENTIFY_LUNMASK;
  616                 if (aic->tinfo[aic->target].lubusy & (1 << aic->lun))
  617                         aic_reconnect(aic, -1);
  618                 else
  619                         aic->state = AIC_RECONNECTING;
  620                 return;
  621         }
  622 
  623         if (aic->state == AIC_RECONNECTING) {
  624                 if (aic->msg_buf[0] != MSG_SIMPLE_Q_TAG) {
  625                         aic_sched_msgout(aic, MSG_MESSAGE_REJECT);
  626                         return;
  627                 }
  628                 aic_reconnect(aic, aic->msg_buf[1]);
  629                 return;
  630         }
  631 
  632         switch (aic->msg_buf[0]) {
  633         case MSG_CMDCOMPLETE: {
  634                 struct ccb_scsiio *csio;
  635                 scb = aic->nexus;
  636                 ccb_h = &scb->ccb->ccb_h;
  637                 csio = &scb->ccb->csio;
  638                 if ((scb->flags & SCB_SENSE) != 0) {
  639                         /* auto REQUEST SENSE command */
  640                         scb->flags &= ~SCB_SENSE;
  641                         csio->sense_resid = scb->data_len;
  642                         if (scb->status == SCSI_STATUS_OK) {
  643                                 ccb_h->status |=
  644                                     CAM_SCSI_STATUS_ERROR|CAM_AUTOSNS_VALID;
  645                                 /*scsi_sense_print(csio);*/
  646                         } else {
  647                                 ccb_h->status |= CAM_AUTOSENSE_FAIL;
  648                                 printf("ccb %p sense failed %x\n",
  649                                     ccb_h, scb->status);
  650                         }
  651                 } else {
  652                         csio->scsi_status = scb->status;
  653                         csio->resid = scb->data_len;
  654                         if (scb->status == SCSI_STATUS_OK) {
  655                                 /* everything goes well */
  656                                 ccb_h->status |= CAM_REQ_CMP;
  657                         } else if ((ccb_h->flags & CAM_DIS_AUTOSENSE) == 0 &&
  658                             (csio->scsi_status == SCSI_STATUS_CHECK_COND ||
  659                              csio->scsi_status == SCSI_STATUS_CMD_TERMINATED)) {
  660                                 /* try to retrieve sense information */
  661                                 scb->flags |= SCB_SENSE;
  662                                 aic->flags |= AIC_BUSFREE_OK;
  663                                 return;
  664                         } else
  665                                 ccb_h->status |= CAM_SCSI_STATUS_ERROR;
  666                 }
  667                 aic_done(aic, scb);
  668                 aic->flags |= AIC_BUSFREE_OK;
  669                 break;
  670         }
  671         case MSG_EXTENDED:
  672                 switch (aic->msg_buf[2]) {
  673                 case MSG_EXT_SDTR:
  674                         scb = aic->nexus;
  675                         ti = &aic->tinfo[scb->target];
  676                         if (ti->flags & TINFO_SDTR_SENT) {
  677                                 ti->current.period = aic->msg_buf[3];
  678                                 ti->current.offset = aic->msg_buf[4];
  679                         } else {
  680                                 ti->current.period = aic->msg_buf[3] =
  681                                         max(ti->goal.period, aic->msg_buf[3]);
  682                                 ti->current.offset = aic->msg_buf[4] =
  683                                         min(ti->goal.offset, aic->msg_buf[4]);
  684                                 /*
  685                                  * The target initiated the negotiation,
  686                                  * send back a response.
  687                                  */
  688                                 aic_sched_msgout(aic, 0);
  689                         }
  690                         ti->flags &= ~(TINFO_SDTR_SENT|TINFO_SDTR_NEGO);
  691                         ti->scsirate = ti->current.offset ? ti->current.offset |
  692                             ((ti->current.period * 4 + 49) / 50 - 2) << 4 : 0;
  693                         aic_outb(aic, SCSIRATE, ti->scsirate);
  694                         memset(&neg, 0, sizeof (neg));
  695                         neg.protocol = PROTO_SCSI;
  696                         neg.protocol_version = SCSI_REV_2;
  697                         neg.transport = XPORT_SPI;
  698                         neg.transport_version = 2;
  699                         spi->sync_period = ti->goal.period = ti->current.period;
  700                         spi->sync_offset = ti->goal.offset = ti->current.offset;
  701                         spi->valid = CTS_SPI_VALID_SYNC_RATE
  702                                   | CTS_SPI_VALID_SYNC_OFFSET;
  703                         ccb_h = &scb->ccb->ccb_h;
  704                         xpt_setup_ccb(&neg.ccb_h, ccb_h->path, 1);
  705                         xpt_async(AC_TRANSFER_NEG, ccb_h->path, &neg);
  706                         break;
  707                 case MSG_EXT_WDTR:
  708                 default:
  709                         aic_sched_msgout(aic, MSG_MESSAGE_REJECT);
  710                         break;
  711                 }
  712                 break;
  713         case MSG_DISCONNECT:
  714                 scb = aic->nexus;
  715                 ccb_h = &scb->ccb->ccb_h;
  716                 TAILQ_INSERT_TAIL(&aic->nexus_ccbs, ccb_h, sim_links.tqe);
  717                 scb->flags |= SCB_DISCONNECTED;
  718                 aic->flags |= AIC_BUSFREE_OK;
  719                 aic->nexus = NULL;
  720                 CAM_DEBUG(ccb_h->path, CAM_DEBUG_TRACE, ("disconnected\n"));
  721                 break;
  722         case MSG_MESSAGE_REJECT:
  723                 switch (aic->msg_outq & -aic->msg_outq) {
  724                 case AIC_MSG_TAG_Q:
  725                         scb = aic->nexus;
  726                         ti = &aic->tinfo[scb->target];
  727                         ti->flags &= ~TINFO_TAG_ENB;
  728                         ti->lubusy |= 1 << scb->lun;
  729                         break;
  730                 case AIC_MSG_SDTR:
  731                         scb = aic->nexus;
  732                         ti = &aic->tinfo[scb->target];
  733                         ti->current.period = ti->goal.period = 0;
  734                         ti->current.offset = ti->goal.offset = 0;
  735                         ti->flags &= ~(TINFO_SDTR_SENT|TINFO_SDTR_NEGO);
  736                         ti->scsirate = 0;
  737                         aic_outb(aic, SCSIRATE, ti->scsirate);
  738                         memset(&neg, 0, sizeof (neg));
  739                         neg.protocol = PROTO_SCSI;
  740                         neg.protocol_version = SCSI_REV_2;
  741                         neg.transport = XPORT_SPI;
  742                         neg.transport_version = 2;
  743                         spi->sync_period = ti->current.period;
  744                         spi->sync_offset = ti->current.offset;
  745                         spi->valid = CTS_SPI_VALID_SYNC_RATE
  746                                   | CTS_SPI_VALID_SYNC_OFFSET;
  747                         ccb_h = &scb->ccb->ccb_h;
  748                         xpt_setup_ccb(&neg.ccb_h, ccb_h->path, 1);
  749                         xpt_async(AC_TRANSFER_NEG, ccb_h->path, &neg);
  750                         break;
  751                 default:
  752                         break;
  753                 }
  754                 break;
  755         case MSG_SAVEDATAPOINTER:
  756                 break;  
  757         case MSG_RESTOREPOINTERS:
  758                 break;
  759         case MSG_NOOP:
  760                 break;
  761         default:
  762                 aic_sched_msgout(aic, MSG_MESSAGE_REJECT);
  763                 break;
  764         }
  765 }
  766 
  767 /*
  768  * Send messages.
  769  */
  770 static void
  771 aic_msgout(struct aic_softc *aic)
  772 {
  773         struct aic_scb *scb;
  774         union ccb *ccb;
  775         struct aic_tinfo *ti;
  776         int msgidx = 0;
  777 
  778         CAM_DEBUG_PRINT(CAM_DEBUG_TRACE, ("aic_msgout\n"));
  779 
  780         aic_outb(aic, SIMODE1, ENSCSIRST|ENPHASEMIS|ENBUSFREE);
  781         aic_outb(aic, SXFRCTL0, CHEN|SPIOEN);
  782 
  783         /*
  784          * If the previous phase is also the message out phase,
  785          * we need to retransmit all the messages, probably
  786          * because the target has detected a parity error during
  787          * the past transmission.
  788          */
  789         if (aic->prev_phase == PH_MSGOUT)
  790                 aic->msg_outq = aic->msg_sent;
  791 
  792         do {
  793                 int q = aic->msg_outq;
  794                 if (msgidx > 0 && msgidx == aic->msg_len) {
  795                         /* complete message sent, start the next one */
  796                         q &= -q;
  797                         aic->msg_sent |= q;
  798                         aic->msg_outq ^= q;
  799                         q = aic->msg_outq;
  800                         msgidx = 0;
  801                 }
  802                 if (msgidx == 0) {
  803                         /* setup the message */
  804                         switch (q & -q) {
  805                         case AIC_MSG_IDENTIFY:
  806                                 scb = aic->nexus;
  807                                 ccb = scb->ccb;
  808                                 ti = &aic->tinfo[scb->target];
  809                                 aic->msg_buf[0] = MSG_IDENTIFY(scb->lun,
  810                                     (ti->flags & TINFO_DISC_ENB) &&
  811                                     !(ccb->ccb_h.flags & CAM_DIS_DISCONNECT));
  812                                 aic->msg_len = 1;
  813                                 break;
  814                         case AIC_MSG_TAG_Q:
  815                                 scb = aic->nexus;
  816                                 ccb = scb->ccb;
  817                                 aic->msg_buf[0] = ccb->csio.tag_action;
  818                                 aic->msg_buf[1] = scb->tag;
  819                                 aic->msg_len = 2;
  820                                 break;
  821                         case AIC_MSG_SDTR:
  822                                 scb = aic->nexus;
  823                                 ti = &aic->tinfo[scb->target];
  824                                 aic->msg_buf[0] = MSG_EXTENDED;
  825                                 aic->msg_buf[1] = MSG_EXT_SDTR_LEN;
  826                                 aic->msg_buf[2] = MSG_EXT_SDTR;
  827                                 aic->msg_buf[3] = ti->goal.period;
  828                                 aic->msg_buf[4] = ti->goal.offset;
  829                                 aic->msg_len = MSG_EXT_SDTR_LEN + 2;
  830                                 ti->flags |= TINFO_SDTR_SENT;
  831                                 break;
  832                         case AIC_MSG_MSGBUF:
  833                                 /* a single message already in the buffer */
  834                                 if (aic->msg_buf[0] == MSG_BUS_DEV_RESET ||
  835                                     aic->msg_buf[0] == MSG_ABORT ||
  836                                     aic->msg_buf[0] == MSG_ABORT_TAG)
  837                                         aic->flags |= AIC_BUSFREE_OK;
  838                                 break;
  839                         }
  840                 }
  841                 /*
  842                  * If this is the last message byte of all messages,
  843                  * clear ATNO to signal transmission complete.
  844                  */
  845                 if ((q & (q - 1)) == 0 && msgidx == aic->msg_len - 1)
  846                         aic_outb(aic, CLRSINT1, CLRATNO);
  847                 /* transmit the message byte */
  848                 aic_outb(aic, SCSIDAT, aic->msg_buf[msgidx++]);
  849         } while (aic_spiordy(aic));
  850 
  851         aic_outb(aic, SXFRCTL0, CHEN);
  852         aic_outb(aic, SIMODE1, ENSCSIRST|ENBUSFREE|ENREQINIT);
  853 }
  854 
  855 /*
  856  * Read data bytes.
  857  */
  858 static void
  859 aic_datain(struct aic_softc *aic)
  860 {
  861         struct aic_scb *scb = aic->nexus;
  862         u_int8_t dmastat, dmacntrl0;
  863         int n;
  864 
  865         CAM_DEBUG_PRINT(CAM_DEBUG_TRACE, ("aic_datain\n"));
  866 
  867         aic_outb(aic, SIMODE1, ENSCSIRST|ENPHASEMIS|ENBUSFREE);
  868         aic_outb(aic, SXFRCTL0, SCSIEN|DMAEN|CHEN);
  869 
  870         dmacntrl0 = ENDMA;
  871         if (aic->flags & AIC_DWIO_ENABLE)
  872                 dmacntrl0 |= DWORDPIO;
  873         aic_outb(aic, DMACNTRL0, dmacntrl0);
  874 
  875         while (scb->data_len > 0) {
  876                 for (;;) {
  877                         /* wait for the fifo to fill up or a phase change */
  878                         dmastat = aic_inb(aic, DMASTAT);
  879                         if (dmastat & (INTSTAT|DFIFOFULL))
  880                                 break;
  881                 }
  882                 if (dmastat & DFIFOFULL) {
  883                         n = FIFOSIZE;
  884                 } else {
  885                         /*
  886                          * No more data, wait for the remaining bytes in
  887                          * the scsi fifo to be transfer to the host fifo.
  888                          */
  889                         while (!(aic_inb(aic, SSTAT2) & SEMPTY))
  890                                 ;
  891                         n = aic_inb(aic, FIFOSTAT);
  892                 }
  893                 n = imin(scb->data_len, n);
  894                 if (aic->flags & AIC_DWIO_ENABLE) {
  895                         if (n >= 12) {
  896                                 aic_insl(aic, DMADATALONG, scb->data_ptr, n>>2);
  897                                 scb->data_ptr += n & ~3;
  898                                 scb->data_len -= n & ~3;
  899                                 n &= 3;
  900                         }
  901                 } else {
  902                         if (n >= 8) {
  903                                 aic_insw(aic, DMADATA, scb->data_ptr, n >> 1);
  904                                 scb->data_ptr += n & ~1;
  905                                 scb->data_len -= n & ~1;
  906                                 n &= 1;
  907                         }
  908                 }
  909                 if (n) {
  910                         aic_outb(aic, DMACNTRL0, ENDMA|B8MODE);
  911                         aic_insb(aic, DMADATA, scb->data_ptr, n);
  912                         scb->data_ptr += n;
  913                         scb->data_len -= n;
  914                         aic_outb(aic, DMACNTRL0, dmacntrl0);
  915                 }
  916 
  917                 if (dmastat & INTSTAT)
  918                         break;
  919         }
  920 
  921         aic_outb(aic, SXFRCTL0, CHEN);
  922         aic_outb(aic, SIMODE1, ENSCSIRST|ENBUSFREE|ENREQINIT);
  923 }
  924 
  925 /*
  926  * Send data bytes.
  927  */
  928 static void
  929 aic_dataout(struct aic_softc *aic)
  930 {
  931         struct aic_scb *scb = aic->nexus;
  932         u_int8_t dmastat, dmacntrl0, sstat2;
  933         int n;
  934 
  935         CAM_DEBUG_PRINT(CAM_DEBUG_TRACE, ("aic_dataout\n"));
  936 
  937         aic_outb(aic, SIMODE1, ENSCSIRST|ENPHASEMIS|ENBUSFREE);
  938         aic_outb(aic, SXFRCTL0, SCSIEN|DMAEN|CHEN);
  939 
  940         dmacntrl0 = ENDMA|WRITE;
  941         if (aic->flags & AIC_DWIO_ENABLE)
  942                 dmacntrl0 |= DWORDPIO;
  943         aic_outb(aic, DMACNTRL0, dmacntrl0);
  944 
  945         while (scb->data_len > 0) {
  946                 for (;;) {
  947                         /* wait for the fifo to clear up or a phase change */
  948                         dmastat = aic_inb(aic, DMASTAT);
  949                         if (dmastat & (INTSTAT|DFIFOEMP))
  950                                 break;
  951                 }
  952                 if (dmastat & INTSTAT)
  953                         break;
  954                 n = imin(scb->data_len, FIFOSIZE);
  955                 if (aic->flags & AIC_DWIO_ENABLE) {
  956                         if (n >= 12) {
  957                                 aic_outsl(aic, DMADATALONG, scb->data_ptr,n>>2);
  958                                 scb->data_ptr += n & ~3;
  959                                 scb->data_len -= n & ~3;
  960                                 n &= 3;
  961                         }
  962                 } else {
  963                         if (n >= 8) {
  964                                 aic_outsw(aic, DMADATA, scb->data_ptr, n >> 1);
  965                                 scb->data_ptr += n & ~1;
  966                                 scb->data_len -= n & ~1;
  967                                 n &= 1;
  968                         }
  969                 }
  970                 if (n) {
  971                         aic_outb(aic, DMACNTRL0, ENDMA|WRITE|B8MODE);
  972                         aic_outsb(aic, DMADATA, scb->data_ptr, n);
  973                         scb->data_ptr += n;
  974                         scb->data_len -= n;
  975                         aic_outb(aic, DMACNTRL0, dmacntrl0);
  976                 }
  977         }
  978 
  979         for (;;) {
  980                 /* wait until all bytes in the fifos are transmitted */
  981                 dmastat = aic_inb(aic, DMASTAT);
  982                 sstat2 = aic_inb(aic, SSTAT2);
  983                 if ((dmastat & DFIFOEMP) && (sstat2 & SEMPTY))
  984                         break;
  985                 if (dmastat & INTSTAT) {
  986                         /* adjust for untransmitted bytes */
  987                         n = aic_inb(aic, FIFOSTAT) + (sstat2 & 0xf);
  988                         scb->data_ptr -= n;
  989                         scb->data_len += n;
  990                         /* clear the fifo */
  991                         aic_outb(aic, SXFRCTL0, CHEN|CLRCH);
  992                         aic_outb(aic, DMACNTRL0, RSTFIFO);
  993                         break;
  994                 }
  995         }
  996 
  997         aic_outb(aic, SXFRCTL0, CHEN);
  998         aic_outb(aic, SIMODE1, ENSCSIRST|ENBUSFREE|ENREQINIT);
  999 }
 1000 
 1001 /*
 1002  * Send the scsi command.
 1003  */
 1004 static void
 1005 aic_cmd(struct aic_softc *aic)
 1006 {
 1007         struct aic_scb *scb = aic->nexus;
 1008         struct scsi_request_sense sense_cmd;
 1009 
 1010         CAM_DEBUG_PRINT(CAM_DEBUG_TRACE, ("aic_cmd\n"));
 1011 
 1012         if (scb->flags & SCB_SENSE) {
 1013                 /* autosense request */
 1014                 sense_cmd.opcode = REQUEST_SENSE;
 1015                 sense_cmd.byte2 = scb->lun << 5;
 1016                 sense_cmd.length = scb->ccb->csio.sense_len;
 1017                 sense_cmd.control = 0;
 1018                 sense_cmd.unused[0] = 0;
 1019                 sense_cmd.unused[1] = 0;
 1020                 scb->cmd_ptr = (u_int8_t *)&sense_cmd;
 1021                 scb->cmd_len = sizeof(sense_cmd);
 1022                 scb->data_ptr = (u_int8_t *)&scb->ccb->csio.sense_data;
 1023                 scb->data_len = scb->ccb->csio.sense_len;
 1024         }
 1025 
 1026         aic_outb(aic, SIMODE1, ENSCSIRST|ENPHASEMIS|ENBUSFREE);
 1027         aic_outb(aic, DMACNTRL0, ENDMA|WRITE);
 1028         aic_outb(aic, SXFRCTL0, SCSIEN|DMAEN|CHEN);
 1029         aic_outsw(aic, DMADATA, (u_int16_t *)scb->cmd_ptr, scb->cmd_len >> 1);
 1030         while ((aic_inb(aic, SSTAT2) & SEMPTY) == 0 &&
 1031             (aic_inb(aic, DMASTAT) & INTSTAT) == 0)
 1032                 ;
 1033         aic_outb(aic, SXFRCTL0, CHEN);
 1034         aic_outb(aic, SIMODE1, ENSCSIRST|ENBUSFREE|ENREQINIT);
 1035 }
 1036 
 1037 /*
 1038  * Finish off a command. The caller is responsible to remove the ccb
 1039  * from any queue.
 1040  */
 1041 static void
 1042 aic_done(struct aic_softc *aic, struct aic_scb *scb)
 1043 {
 1044         union ccb *ccb = scb->ccb;
 1045 
 1046         CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
 1047                   ("aic_done - ccb %p status %x resid %d\n",
 1048                    ccb, ccb->ccb_h.status, ccb->csio.resid));
 1049 
 1050         callout_stop(&scb->timer);
 1051 
 1052         if ((scb->flags & SCB_DEVICE_RESET) != 0 &&
 1053             ccb->ccb_h.func_code != XPT_RESET_DEV) {
 1054                 struct cam_path *path;
 1055                 struct ccb_hdr *ccb_h;
 1056                 cam_status error;
 1057 
 1058                 error = xpt_create_path(&path, /*periph*/NULL,
 1059                                         cam_sim_path(aic->sim),
 1060                                         scb->target,
 1061                                         CAM_LUN_WILDCARD);
 1062 
 1063                 if (error == CAM_REQ_CMP) {
 1064                         xpt_async(AC_SENT_BDR, path, NULL);
 1065                         xpt_free_path(path);
 1066                 }
 1067 
 1068                 ccb_h = TAILQ_FIRST(&aic->pending_ccbs);
 1069                 while (ccb_h != NULL) {
 1070                         struct aic_scb *pending_scb;
 1071 
 1072                         pending_scb = (struct aic_scb *)ccb_h->ccb_scb_ptr;
 1073                         if (ccb_h->target_id == scb->target) {
 1074                                 ccb_h->status |= CAM_BDR_SENT;
 1075                                 ccb_h = TAILQ_NEXT(ccb_h, sim_links.tqe);
 1076                                 TAILQ_REMOVE(&aic->pending_ccbs,
 1077                                     &pending_scb->ccb->ccb_h, sim_links.tqe);
 1078                                 aic_done(aic, pending_scb);
 1079                         } else {
 1080                                 callout_reset_sbt(&pending_scb->timer,
 1081                                     SBT_1MS * ccb_h->timeout, 0, aic_timeout,
 1082                                     pending_scb, 0);
 1083                                 ccb_h = TAILQ_NEXT(ccb_h, sim_links.tqe);
 1084                         }
 1085                 }
 1086 
 1087                 ccb_h = TAILQ_FIRST(&aic->nexus_ccbs);
 1088                 while (ccb_h != NULL) {
 1089                         struct aic_scb *nexus_scb;
 1090 
 1091                         nexus_scb = (struct aic_scb *)ccb_h->ccb_scb_ptr;
 1092                         if (ccb_h->target_id == scb->target) {
 1093                                 ccb_h->status |= CAM_BDR_SENT;
 1094                                 ccb_h = TAILQ_NEXT(ccb_h, sim_links.tqe);
 1095                                 TAILQ_REMOVE(&aic->nexus_ccbs,
 1096                                     &nexus_scb->ccb->ccb_h, sim_links.tqe);
 1097                                 aic_done(aic, nexus_scb);
 1098                         } else {
 1099                                 callout_reset_sbt(&nexus_scb->timer,
 1100                                     SBT_1MS * ccb_h->timeout, 0, aic_timeout,
 1101                                     nexus_scb, 0);
 1102                                 ccb_h = TAILQ_NEXT(ccb_h, sim_links.tqe);
 1103                         }
 1104                 }
 1105         }
 1106 
 1107         if (aic->nexus == scb || scb->flags & SCB_DISCONNECTED)
 1108                 aic->tinfo[scb->target].lubusy &= ~(1 << scb->lun);
 1109         
 1110         if (aic->nexus == scb) {
 1111                 aic->nexus = NULL;
 1112         }
 1113         aic_free_scb(aic, scb);
 1114         xpt_done(ccb);
 1115 }
 1116 
 1117 static void
 1118 aic_poll(struct cam_sim *sim)
 1119 {
 1120         aic_intr_locked(cam_sim_softc(sim));
 1121 }
 1122 
 1123 static void
 1124 aic_timeout(void *arg)
 1125 {
 1126         struct aic_scb *scb = (struct aic_scb *)arg;
 1127         union ccb *ccb = scb->ccb;
 1128         struct aic_softc *aic = (struct aic_softc *)ccb->ccb_h.ccb_aic_ptr;
 1129 
 1130         mtx_assert(&aic->lock, MA_OWNED);
 1131         xpt_print_path(ccb->ccb_h.path);
 1132         printf("ccb %p - timed out", ccb);
 1133         if (aic->nexus && aic->nexus != scb)
 1134                 printf(", nexus %p", aic->nexus->ccb);
 1135         printf(", phase 0x%x, state %d\n", aic_inb(aic, SCSISIGI), aic->state);
 1136 
 1137         if ((scb->flags & SCB_ACTIVE) == 0) {
 1138                 xpt_print_path(ccb->ccb_h.path);
 1139                 printf("ccb %p - timed out already completed\n", ccb);
 1140                 return;
 1141         }
 1142 
 1143         if ((scb->flags & SCB_DEVICE_RESET) == 0 && aic->nexus == scb) {
 1144                 struct ccb_hdr *ccb_h = &scb->ccb->ccb_h;
 1145                 struct aic_scb *pending_scb;
 1146 
 1147                 if ((ccb_h->status & CAM_RELEASE_SIMQ) == 0) {
 1148                         xpt_freeze_simq(aic->sim, /*count*/1);
 1149                         ccb_h->status |= CAM_RELEASE_SIMQ;
 1150                 }
 1151 
 1152                 TAILQ_FOREACH(ccb_h, &aic->pending_ccbs, sim_links.tqe) {
 1153                         pending_scb = ccb_h->ccb_scb_ptr;
 1154                         callout_stop(&pending_scb->timer);
 1155                 }
 1156 
 1157                 TAILQ_FOREACH(ccb_h, &aic->nexus_ccbs, sim_links.tqe) {
 1158                         pending_scb = ccb_h->ccb_scb_ptr;
 1159                         callout_stop(&pending_scb->timer);
 1160                 }
 1161 
 1162                 scb->flags |= SCB_DEVICE_RESET;
 1163                 callout_reset(&scb->timer, 5 * hz, aic_timeout, scb);
 1164                 aic_sched_msgout(aic, MSG_BUS_DEV_RESET);
 1165         } else {
 1166                 if (aic->nexus == scb) {
 1167                         ccb->ccb_h.status |= CAM_CMD_TIMEOUT;
 1168                         aic_done(aic, scb);
 1169                 }
 1170                 aic_reset(aic, /*initiate_reset*/TRUE);
 1171         }
 1172 }
 1173 
 1174 void
 1175 aic_intr(void *arg)
 1176 {
 1177         struct aic_softc *aic = (struct aic_softc *)arg;
 1178 
 1179         mtx_lock(&aic->lock);
 1180         aic_intr_locked(aic);
 1181         mtx_unlock(&aic->lock);
 1182 }
 1183 
 1184 void
 1185 aic_intr_locked(struct aic_softc *aic)
 1186 {
 1187         u_int8_t sstat0, sstat1;
 1188         union ccb *ccb;
 1189         struct aic_scb *scb;
 1190 
 1191         if (!(aic_inb(aic, DMASTAT) & INTSTAT))
 1192                 return;
 1193 
 1194         aic_outb(aic, DMACNTRL0, 0);
 1195 
 1196         sstat0 = aic_inb(aic, SSTAT0);
 1197         sstat1 = aic_inb(aic, SSTAT1);
 1198 
 1199         if ((sstat1 & SCSIRSTI) != 0) {
 1200                 /* a device-initiated bus reset */
 1201                 aic_outb(aic, CLRSINT1, CLRSCSIRSTI);
 1202                 aic_reset(aic, /*initiate_reset*/FALSE);
 1203                 return;
 1204         }
 1205 
 1206         if ((sstat1 & SCSIPERR) != 0) {
 1207                 aic_outb(aic, CLRSINT1, CLRSCSIPERR);
 1208                 aic_sched_msgout(aic, MSG_PARITY_ERROR);
 1209                 aic_outb(aic, DMACNTRL0, INTEN);
 1210                 return;
 1211         }
 1212 
 1213         if (aic_inb(aic, SSTAT4)) {
 1214                 aic_outb(aic, CLRSERR, CLRSYNCERR|CLRFWERR|CLRFRERR);
 1215                 aic_reset(aic, /*initiate_reset*/TRUE);
 1216                 return;
 1217         }
 1218 
 1219         if (aic->state <= AIC_SELECTING) {
 1220                 if ((sstat0 & SELDI) != 0) {
 1221                         aic_reselected(aic);
 1222                         aic_outb(aic, DMACNTRL0, INTEN);
 1223                         return;
 1224                 }
 1225 
 1226                 if ((sstat0 & SELDO) != 0) {
 1227                         aic_selected(aic);
 1228                         aic_outb(aic, DMACNTRL0, INTEN);
 1229                         return;
 1230                 }
 1231 
 1232                 if ((sstat1 & SELTO) != 0) {
 1233                         scb = aic->nexus;
 1234                         ccb = scb->ccb;
 1235                         ccb->ccb_h.status = CAM_SEL_TIMEOUT;
 1236                         aic_done(aic, scb);
 1237                         while ((sstat1 & BUSFREE) == 0)
 1238                                 sstat1 = aic_inb(aic, SSTAT1);
 1239                         aic->flags |= AIC_BUSFREE_OK;
 1240                 }
 1241         }
 1242 
 1243         if ((sstat1 & BUSFREE) != 0) {
 1244                 aic_outb(aic, SCSISEQ, 0);
 1245                 aic_outb(aic, CLRSINT0, sstat0);
 1246                 aic_outb(aic, CLRSINT1, sstat1);
 1247                 if ((scb = aic->nexus)) {
 1248                         if ((aic->flags & AIC_BUSFREE_OK) == 0) {
 1249                                 ccb = scb->ccb;
 1250                                 ccb->ccb_h.status = CAM_UNEXP_BUSFREE;
 1251                                 aic_done(aic, scb);
 1252                         } else if (scb->flags & SCB_DEVICE_RESET) {
 1253                                 ccb = scb->ccb;
 1254                                 if (ccb->ccb_h.func_code == XPT_RESET_DEV) {
 1255                                         xpt_async(AC_SENT_BDR,
 1256                                             ccb->ccb_h.path, NULL);
 1257                                         ccb->ccb_h.status |= CAM_REQ_CMP;
 1258                                 } else
 1259                                         ccb->ccb_h.status |= CAM_CMD_TIMEOUT;
 1260                                 aic_done(aic, scb);
 1261                         } else if (scb->flags & SCB_SENSE) {
 1262                                 /* autosense request */
 1263                                 aic->flags &= ~AIC_BUSFREE_OK;
 1264                                 aic->tinfo[scb->target].lubusy &=
 1265                                     ~(1 << scb->lun);
 1266                                 aic_select(aic);
 1267                                 aic_outb(aic, DMACNTRL0, INTEN);
 1268                                 return;
 1269                         }
 1270                 }
 1271                 aic->flags &= ~AIC_BUSFREE_OK;
 1272                 aic->state = AIC_IDLE;
 1273                 aic_start(aic);
 1274                 aic_outb(aic, DMACNTRL0, INTEN);
 1275                 return;
 1276         }
 1277 
 1278         if ((sstat1 & REQINIT) != 0) {
 1279                 u_int8_t phase = aic_inb(aic, SCSISIGI) & PH_MASK;
 1280                 aic_outb(aic, SCSISIGO, phase);
 1281                 aic_outb(aic, CLRSINT1, CLRPHASECHG);
 1282 
 1283                 switch (phase) {
 1284                 case PH_MSGOUT:
 1285                         aic_msgout(aic);
 1286                         break;
 1287                 case PH_MSGIN:
 1288                         aic_msgin(aic);
 1289                         break;
 1290                 case PH_STAT:
 1291                         scb = aic->nexus;
 1292                         ccb = scb->ccb;
 1293                         aic_outb(aic, DMACNTRL0, 0);
 1294                         aic_outb(aic, SXFRCTL0, CHEN|SPIOEN);
 1295                         scb->status = aic_inb(aic, SCSIDAT);
 1296                         aic_outb(aic, SXFRCTL0, CHEN);
 1297                         break;
 1298                 case PH_CMD:
 1299                         aic_cmd(aic);
 1300                         break;
 1301                 case PH_DATAIN:
 1302                         aic_datain(aic);
 1303                         break;
 1304                 case PH_DATAOUT:
 1305                         aic_dataout(aic);
 1306                         break;
 1307                 }
 1308                 aic->prev_phase = phase;
 1309                 aic_outb(aic, DMACNTRL0, INTEN);
 1310                 return;
 1311         }
 1312 
 1313         printf("aic_intr: unexpected intr sstat0 %x sstat1 %x\n",
 1314                 sstat0, sstat1);
 1315         aic_outb(aic, DMACNTRL0, INTEN);
 1316 }
 1317 
 1318 /*
 1319  * Reset ourselves.
 1320  */
 1321 static void
 1322 aic_chip_reset(struct aic_softc *aic)
 1323 {
 1324         /*
 1325          * Doc. recommends to clear these two registers before
 1326          * operations commence
 1327          */
 1328         aic_outb(aic, SCSITEST, 0);
 1329         aic_outb(aic, TEST, 0);
 1330 
 1331         /* Reset SCSI-FIFO and abort any transfers */
 1332         aic_outb(aic, SXFRCTL0, CHEN|CLRCH|CLRSTCNT);
 1333 
 1334         /* Reset HOST-FIFO */
 1335         aic_outb(aic, DMACNTRL0, RSTFIFO);
 1336         aic_outb(aic, DMACNTRL1, 0);
 1337 
 1338         /* Disable all selection features */
 1339         aic_outb(aic, SCSISEQ, 0);
 1340         aic_outb(aic, SXFRCTL1, 0);
 1341 
 1342         /* Disable interrupts */
 1343         aic_outb(aic, SIMODE0, 0);
 1344         aic_outb(aic, SIMODE1, 0);
 1345 
 1346         /* Clear interrupts */
 1347         aic_outb(aic, CLRSINT0, 0x7f);
 1348         aic_outb(aic, CLRSINT1, 0xef);
 1349 
 1350         /* Disable synchronous transfers */
 1351         aic_outb(aic, SCSIRATE, 0);
 1352 
 1353         /* Haven't seen ant errors (yet) */
 1354         aic_outb(aic, CLRSERR, 0x07);
 1355 
 1356         /* Set our SCSI-ID */
 1357         aic_outb(aic, SCSIID, aic->initiator << OID_S);
 1358         aic_outb(aic, BRSTCNTRL, EISA_BRST_TIM);
 1359 }
 1360 
 1361 /*
 1362  * Reset the SCSI bus
 1363  */
 1364 static void
 1365 aic_scsi_reset(struct aic_softc *aic)
 1366 {
 1367         aic_outb(aic, SCSISEQ, SCSIRSTO);
 1368         DELAY(500);
 1369         aic_outb(aic, SCSISEQ, 0);
 1370         DELAY(50);
 1371 }
 1372 
 1373 /*
 1374  * Reset. Abort all pending commands.
 1375  */
 1376 static void
 1377 aic_reset(struct aic_softc *aic, int initiate_reset)
 1378 {
 1379         struct ccb_hdr *ccb_h;
 1380 
 1381         CAM_DEBUG_PRINT(CAM_DEBUG_TRACE, ("aic_reset\n"));
 1382 
 1383         if (initiate_reset)
 1384                 aic_scsi_reset(aic);
 1385         aic_chip_reset(aic);
 1386 
 1387         xpt_async(AC_BUS_RESET, aic->path, NULL);
 1388 
 1389         while ((ccb_h = TAILQ_FIRST(&aic->pending_ccbs)) != NULL) {
 1390                 TAILQ_REMOVE(&aic->pending_ccbs, ccb_h, sim_links.tqe);
 1391                 ccb_h->status |= CAM_SCSI_BUS_RESET;
 1392                 aic_done(aic, (struct aic_scb *)ccb_h->ccb_scb_ptr);
 1393         }
 1394 
 1395         while ((ccb_h = TAILQ_FIRST(&aic->nexus_ccbs)) != NULL) {
 1396                 TAILQ_REMOVE(&aic->nexus_ccbs, ccb_h, sim_links.tqe);
 1397                 ccb_h->status |= CAM_SCSI_BUS_RESET;
 1398                 aic_done(aic, (struct aic_scb *)ccb_h->ccb_scb_ptr);
 1399         }
 1400 
 1401         if (aic->nexus) {
 1402                 ccb_h = &aic->nexus->ccb->ccb_h;
 1403                 ccb_h->status |= CAM_SCSI_BUS_RESET;
 1404                 aic_done(aic, aic->nexus);
 1405         }
 1406 
 1407         aic->state = AIC_IDLE;
 1408         aic_outb(aic, DMACNTRL0, INTEN);
 1409 }
 1410 
 1411 static char *aic_chip_names[] = {
 1412         "AIC6260", "AIC6360", "AIC6370", "GM82C700",
 1413 };
 1414 
 1415 static struct {
 1416         int type;
 1417         char *idstring;
 1418 } aic_chip_ids[] = {
 1419         { AIC6360, IDSTRING_AIC6360 },
 1420         { AIC6370, IDSTRING_AIC6370 },
 1421         { GM82C700, IDSTRING_GM82C700 },
 1422 };
 1423 
 1424 static void
 1425 aic_init(struct aic_softc *aic)
 1426 {
 1427         struct aic_scb *scb;
 1428         struct aic_tinfo *ti;
 1429         u_int8_t porta, portb;
 1430         char chip_id[33];
 1431         int i;
 1432 
 1433         TAILQ_INIT(&aic->pending_ccbs);
 1434         TAILQ_INIT(&aic->nexus_ccbs);
 1435         SLIST_INIT(&aic->free_scbs);
 1436         aic->nexus = NULL;
 1437         aic->state = AIC_IDLE;
 1438         aic->prev_phase = -1;
 1439         aic->flags = 0;
 1440 
 1441         aic_chip_reset(aic);
 1442         aic_scsi_reset(aic);
 1443 
 1444         /* determine the chip type from its ID string */
 1445         aic->chip_type = AIC6260;
 1446         aic_insb(aic, ID, chip_id, sizeof(chip_id) - 1);
 1447         chip_id[sizeof(chip_id) - 1] = '\0';
 1448         for (i = 0; i < nitems(aic_chip_ids); i++) {
 1449                 if (!strcmp(chip_id, aic_chip_ids[i].idstring)) {
 1450                         aic->chip_type = aic_chip_ids[i].type;
 1451                         break;
 1452                 }
 1453         }
 1454 
 1455         porta = aic_inb(aic, PORTA);
 1456         portb = aic_inb(aic, PORTB);
 1457 
 1458         aic->initiator = PORTA_ID(porta);
 1459         if (PORTA_PARITY(porta))
 1460                 aic->flags |= AIC_PARITY_ENABLE;
 1461         if (PORTB_DISC(portb))
 1462                 aic->flags |= AIC_DISC_ENABLE;
 1463         if (PORTB_DMA(portb))
 1464                 aic->flags |= AIC_DMA_ENABLE;
 1465 
 1466         /*
 1467          * We can do fast SCSI (10MHz clock rate) if bit 4 of portb
 1468          * is set and we've got a 6360.  The 6260 can only do standard
 1469          * 5MHz SCSI.
 1470          */
 1471         if (aic->chip_type > AIC6260 || aic_inb(aic, REV)) {
 1472                 if (PORTB_FSYNC(portb))
 1473                         aic->flags |= AIC_FAST_ENABLE;
 1474                 aic->flags |= AIC_DWIO_ENABLE;
 1475         }
 1476 
 1477         if (aic->flags & AIC_FAST_ENABLE)
 1478                 aic->max_period = AIC_FAST_SYNC_PERIOD;
 1479         else
 1480                 aic->max_period = AIC_SYNC_PERIOD;
 1481         aic->min_period = AIC_MIN_SYNC_PERIOD;
 1482         
 1483         for (i = 255; i >= 0; i--) {
 1484                 scb = &aic->scbs[i];
 1485                 scb->tag = i;
 1486                 callout_init_mtx(&scb->timer, &aic->lock, 0);
 1487                 aic_free_scb(aic, scb);
 1488         }
 1489 
 1490         for (i = 0; i < 8; i++) {
 1491                 if (i == aic->initiator)
 1492                         continue;
 1493                 ti = &aic->tinfo[i];
 1494                 bzero(ti, sizeof(*ti));
 1495                 ti->flags = TINFO_TAG_ENB;
 1496                 if (aic->flags & AIC_DISC_ENABLE)
 1497                         ti->flags |= TINFO_DISC_ENB;
 1498                 ti->user.period = aic->max_period;
 1499                 ti->user.offset = AIC_SYNC_OFFSET;
 1500                 ti->scsirate = 0;
 1501         }
 1502 
 1503         aic_outb(aic, DMACNTRL0, INTEN);
 1504 }
 1505 
 1506 int
 1507 aic_probe(struct aic_softc *aic)
 1508 {
 1509         int i;
 1510 
 1511         /* Remove aic6360 from possible powerdown mode */
 1512         aic_outb(aic, DMACNTRL0, 0);
 1513 
 1514 #define STSIZE  16
 1515         aic_outb(aic, DMACNTRL1, 0);    /* Reset stack pointer */
 1516         for (i = 0; i < STSIZE; i++)
 1517                 aic_outb(aic, STACK, i);
 1518 
 1519         /* See if we can pull out the same sequence */
 1520         aic_outb(aic, DMACNTRL1, 0);
 1521         for (i = 0; i < STSIZE && aic_inb(aic, STACK) == i; i++)
 1522                 ;
 1523         if (i != STSIZE)
 1524                 return (ENXIO);
 1525 #undef  STSIZE
 1526         return (0);
 1527 }
 1528 
 1529 int
 1530 aic_attach(struct aic_softc *aic)
 1531 {
 1532         struct cam_devq *devq;
 1533 
 1534         /*
 1535          * Create the device queue for our SIM.
 1536          */
 1537         devq = cam_simq_alloc(256);
 1538         if (devq == NULL)
 1539                 return (ENOMEM);
 1540 
 1541         /*
 1542          * Construct our SIM entry
 1543          */
 1544         aic->sim = cam_sim_alloc(aic_action, aic_poll, "aic", aic,
 1545             device_get_unit(aic->dev), &aic->lock, 2, 256, devq);
 1546         if (aic->sim == NULL) {
 1547                 cam_simq_free(devq);
 1548                 return (ENOMEM);
 1549         }
 1550 
 1551         mtx_lock(&aic->lock);
 1552         if (xpt_bus_register(aic->sim, aic->dev, 0) != CAM_SUCCESS) {
 1553                 cam_sim_free(aic->sim, /*free_devq*/TRUE);
 1554                 mtx_unlock(&aic->lock);
 1555                 return (ENXIO);
 1556         }
 1557 
 1558         if (xpt_create_path(&aic->path, /*periph*/NULL,
 1559                             cam_sim_path(aic->sim), CAM_TARGET_WILDCARD,
 1560                             CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
 1561                 xpt_bus_deregister(cam_sim_path(aic->sim));
 1562                 cam_sim_free(aic->sim, /*free_devq*/TRUE);
 1563                 mtx_unlock(&aic->lock);
 1564                 return (ENXIO);
 1565         }
 1566 
 1567         aic_init(aic);
 1568 
 1569         device_printf(aic->dev, "%s", aic_chip_names[aic->chip_type]);
 1570         if (aic->flags & AIC_DMA_ENABLE)
 1571                 printf(", dma");
 1572         if (aic->flags & AIC_DISC_ENABLE)
 1573                 printf(", disconnection");
 1574         if (aic->flags & AIC_PARITY_ENABLE)
 1575                 printf(", parity check");
 1576         if (aic->flags & AIC_FAST_ENABLE)
 1577                 printf(", fast SCSI");
 1578         printf("\n");
 1579         mtx_unlock(&aic->lock);
 1580         gone_in_dev(aic->dev, 12, "aic(4) driver");
 1581         return (0);
 1582 }
 1583 
 1584 int
 1585 aic_detach(struct aic_softc *aic)
 1586 {
 1587         struct aic_scb *scb;
 1588         int i;
 1589 
 1590         mtx_lock(&aic->lock);
 1591         xpt_async(AC_LOST_DEVICE, aic->path, NULL);
 1592         xpt_free_path(aic->path);
 1593         xpt_bus_deregister(cam_sim_path(aic->sim));
 1594         cam_sim_free(aic->sim, /*free_devq*/TRUE);
 1595         mtx_unlock(&aic->lock);
 1596         for (i = 255; i >= 0; i--) {
 1597                 scb = &aic->scbs[i];
 1598                 callout_drain(&scb->timer);
 1599         }
 1600         return (0);
 1601 }

Cache object: c8294ca9b8d49209023d7428215842f1


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