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-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

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

Cache object: 0c95af799782fe3fde978e871e57e8b3


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