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

Cache object: 0ac5870ca521a17f14aff0494a8e6cd6


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