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/advansys/adwcam.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * CAM SCSI interface for the the Advanced Systems Inc.
    3  * Second Generation SCSI controllers.
    4  *
    5  * Product specific probe and attach routines can be found in:
    6  * 
    7  * pci/adw_pci.c        ABP940UW
    8  *
    9  * Copyright (c) 1998 Justin Gibbs.
   10  * All rights reserved.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions, and the following disclaimer,
   17  *    without modification, immediately at the beginning of the file.
   18  * 2. The name of the author may not be used to endorse or promote products
   19  *    derived from this software without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   25  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31  * SUCH DAMAGE.
   32  *
   33  * $FreeBSD$
   34  */
   35 /*
   36  * Ported from:
   37  * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
   38  *     
   39  * Copyright (c) 1995-1998 Advanced System Products, Inc.
   40  * All Rights Reserved.
   41  *   
   42  * Redistribution and use in source and binary forms, with or without
   43  * modification, are permitted provided that redistributions of source
   44  * code retain the above copyright notice and this comment without
   45  * modification.
   46  */
   47 #include <stddef.h>     /* For offsetof */
   48 
   49 #include <sys/param.h>
   50 #include <sys/systm.h>
   51 #include <sys/kernel.h>
   52 #include <sys/malloc.h>
   53 
   54 #include <machine/bus_pio.h>
   55 #include <machine/bus_memio.h>
   56 #include <machine/bus.h>
   57 #include <machine/clock.h>
   58 
   59 #include <cam/cam.h>
   60 #include <cam/cam_ccb.h>
   61 #include <cam/cam_sim.h>
   62 #include <cam/cam_xpt_sim.h>
   63 #include <cam/cam_debug.h>
   64 
   65 #include <cam/scsi/scsi_message.h>
   66 
   67 #include <dev/advansys/adwvar.h>
   68 
   69 /* Definitions for our use of the SIM private CCB area */
   70 #define ccb_acb_ptr spriv_ptr0
   71 #define ccb_adw_ptr spriv_ptr1
   72 
   73 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
   74 
   75 u_long adw_unit;
   76 
   77 static __inline u_int32_t       acbvtop(struct adw_softc *adw,
   78                                            struct acb *acb);
   79 static __inline struct acb *    acbptov(struct adw_softc *adw,
   80                                         u_int32_t busaddr);
   81 static __inline struct acb*     adwgetacb(struct adw_softc *adw);
   82 static __inline void            adwfreeacb(struct adw_softc *adw,
   83                                            struct acb *acb);
   84 
   85 static void             adwmapmem(void *arg, bus_dma_segment_t *segs,
   86                                   int nseg, int error);
   87 static struct sg_map_node*
   88                         adwallocsgmap(struct adw_softc *adw);
   89 static int              adwallocacbs(struct adw_softc *adw);
   90 
   91 static void             adwexecuteacb(void *arg, bus_dma_segment_t *dm_segs,
   92                                       int nseg, int error);
   93 static void             adw_action(struct cam_sim *sim, union ccb *ccb);
   94 static void             adw_poll(struct cam_sim *sim);
   95 static void             adw_async(void *callback_arg, u_int32_t code,
   96                                   struct cam_path *path, void *arg);
   97 static void             adwprocesserror(struct adw_softc *adw, struct acb *acb);
   98 static void             adwtimeout(void *arg);
   99 static void             adw_handle_device_reset(struct adw_softc *adw,
  100                                                 u_int target);
  101 static void             adw_handle_bus_reset(struct adw_softc *adw,
  102                                              int initiated);
  103 
  104 static __inline u_int32_t
  105 acbvtop(struct adw_softc *adw, struct acb *acb)
  106 {
  107         return (adw->acb_busbase
  108               + (u_int32_t)((caddr_t)acb - (caddr_t)adw->acbs));
  109 }
  110 
  111 static __inline struct acb *
  112 acbptov(struct adw_softc *adw, u_int32_t busaddr)
  113 {
  114         return (adw->acbs
  115               + ((struct acb *)busaddr - (struct acb *)adw->acb_busbase));
  116 }
  117 
  118 static __inline struct acb*
  119 adwgetacb(struct adw_softc *adw)
  120 {
  121         struct  acb* acb;
  122         int     s;
  123 
  124         s = splcam();
  125         if ((acb = SLIST_FIRST(&adw->free_acb_list)) != NULL) {
  126                 SLIST_REMOVE_HEAD(&adw->free_acb_list, links);
  127         } else if (adw->num_acbs < adw->max_acbs) {
  128                 adwallocacbs(adw);
  129                 acb = SLIST_FIRST(&adw->free_acb_list);
  130                 if (acb == NULL)
  131                         printf("%s: Can't malloc ACB\n", adw_name(adw));
  132                 else {
  133                         SLIST_REMOVE_HEAD(&adw->free_acb_list, links);
  134                 }
  135         }
  136         splx(s);
  137 
  138         return (acb);
  139 }
  140 
  141 static __inline void
  142 adwfreeacb(struct adw_softc *adw, struct acb *acb)
  143 {
  144         int s;
  145 
  146         s = splcam();
  147         if ((acb->state & ACB_ACTIVE) != 0)
  148                 LIST_REMOVE(&acb->ccb->ccb_h, sim_links.le);
  149         if ((acb->state & ACB_RELEASE_SIMQ) != 0)
  150                 acb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
  151         else if ((adw->state & ADW_RESOURCE_SHORTAGE) != 0
  152               && (acb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) {
  153                 acb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
  154                 adw->state &= ~ADW_RESOURCE_SHORTAGE;
  155         }
  156         acb->state = ACB_FREE;
  157         SLIST_INSERT_HEAD(&adw->free_acb_list, acb, links);
  158         splx(s);
  159 }
  160 
  161 static void
  162 adwmapmem(void *arg, bus_dma_segment_t *segs, int nseg, int error)
  163 {
  164         bus_addr_t *busaddrp;
  165 
  166         busaddrp = (bus_addr_t *)arg;
  167         *busaddrp = segs->ds_addr;
  168 }
  169 
  170 static struct sg_map_node *
  171 adwallocsgmap(struct adw_softc *adw)
  172 {
  173         struct sg_map_node *sg_map;
  174 
  175         sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT);
  176 
  177         if (sg_map == NULL)
  178                 return (NULL);
  179 
  180         /* Allocate S/G space for the next batch of ACBS */
  181         if (bus_dmamem_alloc(adw->sg_dmat, (void **)&sg_map->sg_vaddr,
  182                              BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) {
  183                 free(sg_map, M_DEVBUF);
  184                 return (NULL);
  185         }
  186 
  187         SLIST_INSERT_HEAD(&adw->sg_maps, sg_map, links);
  188 
  189         bus_dmamap_load(adw->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr,
  190                         PAGE_SIZE, adwmapmem, &sg_map->sg_physaddr, /*flags*/0);
  191 
  192         bzero(sg_map->sg_vaddr, PAGE_SIZE);
  193         return (sg_map);
  194 }
  195 
  196 /*
  197  * Allocate another chunk of CCB's. Return count of entries added.
  198  * Assumed to be called at splcam().
  199  */
  200 static int
  201 adwallocacbs(struct adw_softc *adw)
  202 {
  203         struct acb *next_acb;
  204         struct sg_map_node *sg_map;
  205         bus_addr_t busaddr;
  206         struct adw_sg_block *blocks;
  207         int newcount;
  208         int i;
  209 
  210         next_acb = &adw->acbs[adw->num_acbs];
  211 
  212         sg_map = adwallocsgmap(adw);
  213 
  214         if (sg_map == NULL)
  215                 return (0);
  216 
  217         blocks = sg_map->sg_vaddr;
  218         busaddr = sg_map->sg_physaddr;
  219 
  220         newcount = (PAGE_SIZE / (ADW_SG_BLOCKCNT * sizeof(*blocks)));
  221         for (i = 0; adw->num_acbs < adw->max_acbs && i < newcount; i++) {
  222                 int error;
  223                 int j;
  224 
  225                 error = bus_dmamap_create(adw->buffer_dmat, /*flags*/0,
  226                                           &next_acb->dmamap);
  227                 if (error != 0)
  228                         break;
  229                 next_acb->queue.scsi_req_baddr = acbvtop(adw, next_acb);
  230                 next_acb->queue.sense_addr =
  231                     acbvtop(adw, next_acb) + offsetof(struct acb, sense_data);
  232                 next_acb->sg_blocks = blocks;
  233                 next_acb->sg_busaddr = busaddr;
  234                 /* Setup static data in the sg blocks */
  235                 for (j = 0; j < ADW_SG_BLOCKCNT; j++) {
  236                         next_acb->sg_blocks[j].first_entry_no =
  237                             j * ADW_NO_OF_SG_PER_BLOCK;
  238                 }
  239                 next_acb->state = ACB_FREE;
  240                 SLIST_INSERT_HEAD(&adw->free_acb_list, next_acb, links);
  241                 blocks += ADW_SG_BLOCKCNT;
  242                 busaddr += ADW_SG_BLOCKCNT * sizeof(*blocks);
  243                 next_acb++;
  244                 adw->num_acbs++;
  245         }
  246         return (i);
  247 }
  248 
  249 static void
  250 adwexecuteacb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
  251 {
  252         struct   acb *acb;
  253         union    ccb *ccb;
  254         struct   adw_softc *adw;
  255         int      s;
  256 
  257         acb = (struct acb *)arg;
  258         ccb = acb->ccb;
  259         adw = (struct adw_softc *)ccb->ccb_h.ccb_adw_ptr;
  260 
  261         if (error != 0) {
  262                 if (error != EFBIG)
  263                         printf("%s: Unexepected error 0x%x returned from "
  264                                "bus_dmamap_load\n", adw_name(adw), error);
  265                 if (ccb->ccb_h.status == CAM_REQ_INPROG) {
  266                         xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
  267                         ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN;
  268                 }
  269                 adwfreeacb(adw, acb);
  270                 xpt_done(ccb);
  271                 return;
  272         }
  273                 
  274         if (nseg != 0) {
  275                 bus_dmasync_op_t op;
  276 
  277                 acb->queue.data_addr = dm_segs[0].ds_addr;
  278                 acb->queue.data_cnt = ccb->csio.dxfer_len;
  279                 if (nseg > 1) {
  280                         struct adw_sg_block *sg_block;
  281                         struct adw_sg_elm *sg;
  282                         bus_addr_t sg_busaddr;
  283                         u_int sg_index;
  284                         bus_dma_segment_t *end_seg;
  285 
  286                         end_seg = dm_segs + nseg;
  287 
  288                         sg_busaddr = acb->sg_busaddr;
  289                         sg_index = 0;
  290                         /* Copy the segments into our SG list */
  291                         for (sg_block = acb->sg_blocks;; sg_block++) {
  292                                 u_int sg_left;
  293 
  294                                 sg_left = ADW_NO_OF_SG_PER_BLOCK;
  295                                 sg = sg_block->sg_list;
  296                                 while (dm_segs < end_seg && sg_left != 0) {
  297                                         sg->sg_addr = dm_segs->ds_addr;
  298                                         sg->sg_count = dm_segs->ds_len;
  299                                         sg++;
  300                                         dm_segs++;
  301                                         sg_left--;
  302                                 }
  303                                 sg_index += ADW_NO_OF_SG_PER_BLOCK - sg_left;
  304                                 sg_block->last_entry_no = sg_index - 1;
  305                                 if (dm_segs == end_seg) {
  306                                         sg_block->sg_busaddr_next = 0;
  307                                         break;
  308                                 } else {
  309                                         sg_busaddr +=
  310                                             sizeof(struct adw_sg_block);
  311                                         sg_block->sg_busaddr_next = sg_busaddr;
  312                                 }
  313                         }
  314 
  315                         acb->queue.sg_entry_cnt = nseg;
  316                         acb->queue.sg_real_addr = acb->sg_busaddr;
  317                 } else {
  318                         acb->queue.sg_entry_cnt = 0;
  319                         acb->queue.sg_real_addr = 0;
  320                 }
  321 
  322                 if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
  323                         op = BUS_DMASYNC_PREREAD;
  324                 else
  325                         op = BUS_DMASYNC_PREWRITE;
  326 
  327                 bus_dmamap_sync(adw->buffer_dmat, acb->dmamap, op);
  328 
  329         } else {
  330                 acb->queue.sg_entry_cnt = 0;
  331                 acb->queue.data_addr = 0;
  332                 acb->queue.data_cnt = 0;
  333                 acb->queue.sg_real_addr = 0;
  334         }
  335         acb->queue.free_scsiq_link = 0;
  336         acb->queue.ux_wk_data_cnt = 0;
  337 
  338         s = splcam();
  339 
  340         /*
  341          * Last time we need to check if this CCB needs to
  342          * be aborted.
  343          */
  344         if (ccb->ccb_h.status != CAM_REQ_INPROG) {
  345                 if (nseg != 0)
  346                         bus_dmamap_unload(adw->buffer_dmat, acb->dmamap);
  347                 adwfreeacb(adw, acb);
  348                 xpt_done(ccb);
  349                 splx(s);
  350                 return;
  351         }
  352                 
  353         acb->state |= ACB_ACTIVE;
  354         ccb->ccb_h.status |= CAM_SIM_QUEUED;
  355         LIST_INSERT_HEAD(&adw->pending_ccbs, &ccb->ccb_h, sim_links.le);
  356         ccb->ccb_h.timeout_ch =
  357             timeout(adwtimeout, (caddr_t)acb,
  358                     (ccb->ccb_h.timeout * hz) / 1000);
  359 
  360         adw_send_acb(adw, acb, acbvtop(adw, acb));
  361 
  362         splx(s);
  363 }
  364 
  365 static void
  366 adw_action(struct cam_sim *sim, union ccb *ccb)
  367 {
  368         struct  adw_softc *adw;
  369 
  370         CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("adw_action\n"));
  371         
  372         adw = (struct adw_softc *)cam_sim_softc(sim);
  373 
  374         switch (ccb->ccb_h.func_code) {
  375         /* Common cases first */
  376         case XPT_SCSI_IO:       /* Execute the requested I/O operation */
  377         {
  378                 struct  ccb_scsiio *csio;
  379                 struct  ccb_hdr *ccbh;
  380                 struct  acb *acb;
  381 
  382                 csio = &ccb->csio;
  383                 ccbh = &ccb->ccb_h;
  384                 /* Max supported CDB length is 12 bytes */
  385                 if (csio->cdb_len > 12) { 
  386                         ccb->ccb_h.status = CAM_REQ_INVALID;
  387                         xpt_done(ccb);
  388                         return;
  389                 }
  390 
  391                 if ((acb = adwgetacb(adw)) == NULL) {
  392                         int s;
  393         
  394                         s = splcam();
  395                         adw->state |= ADW_RESOURCE_SHORTAGE;
  396                         splx(s);
  397                         xpt_freeze_simq(sim, /*count*/1);
  398                         ccb->ccb_h.status = CAM_REQUEUE_REQ;
  399                         xpt_done(ccb);
  400                         return;
  401                 }
  402 
  403                 /* Link dccb and ccb so we can find one from the other */
  404                 acb->ccb = ccb;
  405                 ccb->ccb_h.ccb_acb_ptr = acb;
  406                 ccb->ccb_h.ccb_adw_ptr = adw;
  407 
  408                 acb->queue.cntl = 0;
  409                 acb->queue.target_id = ccb->ccb_h.target_id;
  410                 acb->queue.target_lun = ccb->ccb_h.target_lun;
  411 
  412                 acb->queue.srb_ptr = 0;
  413                 acb->queue.a_flag = 0;
  414                 acb->queue.sense_len =
  415                         MIN(csio->sense_len, sizeof(acb->sense_data));
  416                 acb->queue.cdb_len = csio->cdb_len;
  417 
  418                 if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0)
  419                         acb->queue.tag_code = csio->tag_action;
  420                 else
  421                         acb->queue.tag_code = 0;
  422 
  423                 acb->queue.done_status = 0;
  424                 acb->queue.scsi_status = 0;
  425                 acb->queue.host_status = 0;
  426                 acb->queue.ux_sg_ix = 0;
  427 
  428                 if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
  429                         if ((ccb->ccb_h.flags & CAM_CDB_PHYS) == 0) {
  430                                 bcopy(csio->cdb_io.cdb_ptr,
  431                                       acb->queue.cdb, csio->cdb_len);
  432                         } else {
  433                                 /* I guess I could map it in... */
  434                                 ccb->ccb_h.status = CAM_REQ_INVALID;
  435                                 adwfreeacb(adw, acb);
  436                                 xpt_done(ccb);
  437                                 return;
  438                         }
  439                 } else {
  440                         bcopy(csio->cdb_io.cdb_bytes,
  441                               acb->queue.cdb, csio->cdb_len);
  442                 }
  443 
  444                 /*
  445                  * If we have any data to send with this command,
  446                  * map it into bus space.
  447                  */
  448                 if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
  449                         if ((ccbh->flags & CAM_SCATTER_VALID) == 0) {
  450                                 /*
  451                                  * We've been given a pointer
  452                                  * to a single buffer.
  453                                  */
  454                                 if ((ccbh->flags & CAM_DATA_PHYS) == 0) {
  455                                         int s;
  456                                         int error;
  457 
  458                                         s = splsoftvm();
  459                                         error =
  460                                             bus_dmamap_load(adw->buffer_dmat,
  461                                                             acb->dmamap,
  462                                                             csio->data_ptr,
  463                                                             csio->dxfer_len,
  464                                                             adwexecuteacb,
  465                                                             acb, /*flags*/0);
  466                                         if (error == EINPROGRESS) {
  467                                                 /*
  468                                                  * So as to maintain ordering,
  469                                                  * freeze the controller queue
  470                                                  * until our mapping is
  471                                                  * returned.
  472                                                  */
  473                                                 xpt_freeze_simq(sim, 1);
  474                                                 acb->state |= CAM_RELEASE_SIMQ;
  475                                         }
  476                                         splx(s);
  477                                 } else {
  478                                         struct bus_dma_segment seg; 
  479 
  480                                         /* Pointer to physical buffer */
  481                                         seg.ds_addr =
  482                                             (bus_addr_t)csio->data_ptr;
  483                                         seg.ds_len = csio->dxfer_len;
  484                                         adwexecuteacb(acb, &seg, 1, 0);
  485                                 }
  486                         } else {
  487                                 struct bus_dma_segment *segs;
  488 
  489                                 if ((ccbh->flags & CAM_DATA_PHYS) != 0)
  490                                         panic("adw_action - Physical "
  491                                               "segment pointers "
  492                                               "unsupported");
  493 
  494                                 if ((ccbh->flags&CAM_SG_LIST_PHYS)==0)
  495                                         panic("adw_action - Virtual "
  496                                               "segment addresses "
  497                                               "unsupported");
  498 
  499                                 /* Just use the segments provided */
  500                                 segs = (struct bus_dma_segment *)csio->data_ptr;
  501                                 adwexecuteacb(acb, segs, csio->sglist_cnt,
  502                                               (csio->sglist_cnt < ADW_SGSIZE)
  503                                               ? 0 : EFBIG);
  504                         }
  505                 } else {
  506                         adwexecuteacb(acb, NULL, 0, 0);
  507                 }
  508                 break;
  509         }
  510         case XPT_RESET_DEV:     /* Bus Device Reset the specified SCSI device */
  511         {
  512                 adw_idle_cmd_status_t status;
  513 
  514                 adw_idle_cmd_send(adw, ADW_IDLE_CMD_DEVICE_RESET,
  515                                   ccb->ccb_h.target_id);
  516                 status = adw_idle_cmd_wait(adw);
  517                 if (status == ADW_IDLE_CMD_SUCCESS) {
  518                         ccb->ccb_h.status = CAM_REQ_CMP;
  519                         if (bootverbose) {
  520                                 xpt_print_path(ccb->ccb_h.path);
  521                                 printf("BDR Delivered\n");
  522                         }
  523                 } else
  524                         ccb->ccb_h.status = CAM_REQ_CMP_ERR;
  525                 xpt_done(ccb);
  526                 break;
  527         }
  528         case XPT_ABORT:                 /* Abort the specified CCB */
  529                 /* XXX Implement */
  530                 ccb->ccb_h.status = CAM_REQ_INVALID;
  531                 xpt_done(ccb);
  532                 break;
  533         case XPT_SET_TRAN_SETTINGS:
  534         {
  535                 struct    ccb_trans_settings *cts;
  536                 u_int     target_mask;
  537                 int       s;
  538 
  539                 cts = &ccb->cts;
  540                 target_mask = 0x01 << ccb->ccb_h.target_id;
  541 
  542                 s = splcam();
  543                 if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) {
  544                         if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) {
  545                                 u_int discenb;
  546 
  547                                 discenb =
  548                                     adw_lram_read_16(adw, ADW_MC_DISC_ENABLE);
  549 
  550                                 if ((cts->flags & CCB_TRANS_DISC_ENB) != 0)
  551                                         discenb |= target_mask;
  552                                 else
  553                                         discenb &= ~target_mask;
  554 
  555                                 adw_lram_write_16(adw, ADW_MC_DISC_ENABLE,
  556                                                   discenb);
  557                         }
  558                 
  559                         if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) {
  560 
  561                                 if ((cts->flags & CCB_TRANS_TAG_ENB) != 0)
  562                                         adw->tagenb |= target_mask;
  563                                 else
  564                                         adw->tagenb &= ~target_mask;
  565                         }       
  566 
  567                         if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) != 0) {
  568                                 u_int wdtrenb_orig;
  569                                 u_int wdtrenb;
  570                                 u_int wdtrdone;
  571 
  572                                 wdtrenb_orig =
  573                                     adw_lram_read_16(adw, ADW_MC_WDTR_ABLE);
  574                                 wdtrenb = wdtrenb_orig;
  575                                 wdtrdone = adw_lram_read_16(adw,
  576                                                             ADW_MC_WDTR_DONE);
  577                                 switch (cts->bus_width) {
  578                                 case MSG_EXT_WDTR_BUS_32_BIT:
  579                                 case MSG_EXT_WDTR_BUS_16_BIT:
  580                                         wdtrenb |= target_mask;
  581                                         break;
  582                                 case MSG_EXT_WDTR_BUS_8_BIT:
  583                                 default:
  584                                         wdtrenb &= ~target_mask;
  585                                         break;
  586                                 }
  587                                 if (wdtrenb != wdtrenb_orig) {
  588                                         adw_lram_write_16(adw,
  589                                                           ADW_MC_WDTR_ABLE,
  590                                                           wdtrenb);
  591                                         wdtrdone &= ~target_mask;
  592                                         adw_lram_write_16(adw,
  593                                                           ADW_MC_WDTR_DONE,
  594                                                           wdtrdone);
  595                                 }
  596                         }
  597 
  598                         if (((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0)
  599                          || ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0)) {
  600                                 u_int sdtrenb_orig;
  601                                 u_int sdtrenb;
  602                                 u_int ultraenb_orig;
  603                                 u_int ultraenb;
  604                                 u_int sdtrdone;
  605 
  606                                 sdtrenb_orig =
  607                                     adw_lram_read_16(adw, ADW_MC_SDTR_ABLE);
  608                                 sdtrenb = sdtrenb_orig;
  609 
  610                                 ultraenb_orig =
  611                                     adw_lram_read_16(adw, ADW_MC_ULTRA_ABLE);
  612                                 ultraenb = ultraenb_orig;
  613 
  614                                 sdtrdone = adw_lram_read_16(adw,
  615                                                             ADW_MC_SDTR_DONE);
  616 
  617                                 if ((cts->valid
  618                                    & CCB_TRANS_SYNC_RATE_VALID) != 0) {
  619 
  620                                         if (cts->sync_period == 0) {
  621                                                 sdtrenb &= ~target_mask;
  622                                         } else if (cts->sync_period > 12) {
  623                                                 ultraenb &= ~target_mask;
  624                                                 sdtrenb |= target_mask;
  625                                         } else {
  626                                                 ultraenb |= target_mask;
  627                                                 sdtrenb |= target_mask;
  628                                         }
  629                                 }
  630                                         
  631                                 if ((cts->valid
  632                                    & CCB_TRANS_SYNC_OFFSET_VALID) != 0) {
  633                                         if (cts->sync_offset == 0)
  634                                                 sdtrenb &= ~target_mask;
  635                                 }
  636 
  637                                 if (sdtrenb != sdtrenb_orig
  638                                  || ultraenb != ultraenb_orig) {
  639                                         adw_lram_write_16(adw, ADW_MC_SDTR_ABLE,
  640                                                           sdtrenb);
  641                                         adw_lram_write_16(adw,
  642                                                           ADW_MC_ULTRA_ABLE,
  643                                                           ultraenb);
  644                                         sdtrdone &= ~target_mask;
  645                                         adw_lram_write_16(adw, ADW_MC_SDTR_DONE,
  646                                                           sdtrdone);
  647                                 }
  648                         } 
  649                 }
  650                 splx(s);
  651                 ccb->ccb_h.status = CAM_REQ_CMP;
  652                 xpt_done(ccb);
  653                 break;
  654         }
  655         case XPT_GET_TRAN_SETTINGS:
  656         /* Get default/user set transfer settings for the target */
  657         {
  658                 struct  ccb_trans_settings *cts;
  659                 u_int   target_mask;
  660  
  661                 cts = &ccb->cts;
  662                 target_mask = 0x01 << ccb->ccb_h.target_id;
  663                 if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) { 
  664                         cts->flags = 0;
  665                         if ((adw->user_discenb & target_mask) != 0)
  666                                 cts->flags |= CCB_TRANS_DISC_ENB;
  667 
  668                         if ((adw->user_tagenb & target_mask) != 0)
  669                                 cts->flags |= CCB_TRANS_TAG_ENB;
  670 
  671                         if ((adw->user_wdtr & target_mask) != 0)
  672                                 cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
  673                         else
  674                                 cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
  675 
  676                         if ((adw->user_sdtr & target_mask) != 0) {
  677                                 if ((adw->user_ultra & target_mask) != 0)
  678                                         cts->sync_period = 12; /* 20MHz */
  679                                 else
  680                                         cts->sync_period = 25; /* 10MHz */
  681                                 cts->sync_offset = 15; /* XXX ??? */
  682                         }
  683 
  684                         cts->valid = CCB_TRANS_SYNC_RATE_VALID
  685                                    | CCB_TRANS_SYNC_OFFSET_VALID
  686                                    | CCB_TRANS_BUS_WIDTH_VALID
  687                                    | CCB_TRANS_DISC_VALID
  688                                    | CCB_TRANS_TQ_VALID;
  689                         ccb->ccb_h.status = CAM_REQ_CMP;
  690                 } else {
  691                         u_int targ_tinfo;
  692 
  693                         cts->flags = 0;
  694                         if ((adw_lram_read_16(adw, ADW_MC_DISC_ENABLE)
  695                           & target_mask) != 0)
  696                                 cts->flags |= CCB_TRANS_DISC_ENB;
  697 
  698                         if ((adw->tagenb & target_mask) != 0)
  699                                 cts->flags |= CCB_TRANS_TAG_ENB;
  700 
  701                         targ_tinfo =
  702                             adw_lram_read_16(adw,
  703                                              ADW_MC_DEVICE_HSHK_CFG_TABLE
  704                                              + (2 * ccb->ccb_h.target_id));
  705 
  706                         if ((targ_tinfo & ADW_HSHK_CFG_WIDE_XFR) != 0)
  707                                 cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
  708                         else
  709                                 cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
  710 
  711                         cts->sync_period =
  712                             ADW_HSHK_CFG_PERIOD_FACTOR(targ_tinfo);
  713 
  714                         cts->sync_offset = targ_tinfo & ADW_HSHK_CFG_OFFSET;
  715                         if (cts->sync_period == 0)
  716                                 cts->sync_offset = 0;
  717 
  718                         if (cts->sync_offset == 0)
  719                                 cts->sync_period = 0;
  720                 }
  721                 cts->valid = CCB_TRANS_SYNC_RATE_VALID
  722                            | CCB_TRANS_SYNC_OFFSET_VALID
  723                            | CCB_TRANS_BUS_WIDTH_VALID
  724                            | CCB_TRANS_DISC_VALID
  725                            | CCB_TRANS_TQ_VALID;
  726                 ccb->ccb_h.status = CAM_REQ_CMP;
  727                 xpt_done(ccb);
  728                 break;
  729         }
  730         case XPT_CALC_GEOMETRY:
  731         {
  732                 struct    ccb_calc_geometry *ccg;
  733                 u_int32_t size_mb;
  734                 u_int32_t secs_per_cylinder;
  735                 int       extended;
  736 
  737                 /*
  738                  * XXX Use Adaptec translation until I find out how to
  739                  *     get this information from the card.
  740                  */
  741                 ccg = &ccb->ccg;
  742                 size_mb = ccg->volume_size
  743                         / ((1024L * 1024L) / ccg->block_size);
  744                 extended = 1;
  745                 
  746                 if (size_mb > 1024 && extended) {
  747                         ccg->heads = 255;
  748                         ccg->secs_per_track = 63;
  749                 } else {
  750                         ccg->heads = 64;
  751                         ccg->secs_per_track = 32;
  752                 }
  753                 secs_per_cylinder = ccg->heads * ccg->secs_per_track;
  754                 ccg->cylinders = ccg->volume_size / secs_per_cylinder;
  755                 ccb->ccb_h.status = CAM_REQ_CMP;
  756                 xpt_done(ccb);
  757                 break;
  758         }
  759         case XPT_RESET_BUS:             /* Reset the specified SCSI bus */
  760         {
  761                 adw_idle_cmd_status_t status;
  762 
  763                 adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET, /*param*/0);
  764                 status = adw_idle_cmd_wait(adw);
  765                 if (status == ADW_IDLE_CMD_SUCCESS) {
  766                         ccb->ccb_h.status = CAM_REQ_CMP;
  767                         if (bootverbose) {
  768                                 xpt_print_path(adw->path);
  769                                 printf("Bus Reset Delivered\n");
  770                         }
  771                 } else
  772                         ccb->ccb_h.status = CAM_REQ_CMP_ERR;
  773                 xpt_done(ccb);
  774                 break;
  775         }
  776         case XPT_TERM_IO:               /* Terminate the I/O process */
  777                 /* XXX Implement */
  778                 ccb->ccb_h.status = CAM_REQ_INVALID;
  779                 xpt_done(ccb);
  780                 break;
  781         case XPT_PATH_INQ:              /* Path routing inquiry */
  782         {
  783                 struct ccb_pathinq *cpi = &ccb->cpi;
  784                 
  785                 cpi->version_num = 1;
  786                 cpi->hba_inquiry = PI_WIDE_16|PI_SDTR_ABLE|PI_TAG_ABLE;
  787                 cpi->target_sprt = 0;
  788                 cpi->hba_misc = 0;
  789                 cpi->hba_eng_cnt = 0;
  790                 cpi->max_target = ADW_MAX_TID;
  791                 cpi->max_lun = ADW_MAX_LUN;
  792                 cpi->initiator_id = adw->initiator_id;
  793                 cpi->bus_id = cam_sim_bus(sim);
  794                 cpi->base_transfer_speed = 3300;
  795                 strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
  796                 strncpy(cpi->hba_vid, "AdvanSys", HBA_IDLEN);
  797                 strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
  798                 cpi->unit_number = cam_sim_unit(sim);
  799                 cpi->ccb_h.status = CAM_REQ_CMP;
  800                 xpt_done(ccb);
  801                 break;
  802         }
  803         default:
  804                 ccb->ccb_h.status = CAM_REQ_INVALID;
  805                 xpt_done(ccb);
  806                 break;
  807         }
  808 }
  809 
  810 static void
  811 adw_poll(struct cam_sim *sim)
  812 {
  813         adw_intr(cam_sim_softc(sim));
  814 }
  815 
  816 static void
  817 adw_async(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
  818 {
  819 }
  820 
  821 struct adw_softc *
  822 adw_alloc(int unit, bus_space_tag_t tag, bus_space_handle_t bsh)
  823 {
  824         struct   adw_softc *adw;
  825         int      i;
  826    
  827         /*
  828          * Allocate a storage area for us
  829          */
  830         adw = malloc(sizeof(struct adw_softc), M_DEVBUF, M_NOWAIT);
  831         if (adw == NULL) {
  832                 printf("adw%d: cannot malloc!\n", unit);
  833                 return NULL;
  834         }
  835         bzero(adw, sizeof(struct adw_softc));
  836         LIST_INIT(&adw->pending_ccbs);
  837         SLIST_INIT(&adw->sg_maps);
  838         adw->unit = unit;
  839         adw->tag = tag;
  840         adw->bsh = bsh;
  841         i = adw->unit / 10;
  842         adw->name = malloc(sizeof("adw") + i + 1, M_DEVBUF, M_NOWAIT);
  843         if (adw->name == NULL) {
  844                 printf("adw%d: cannot malloc name!\n", unit);
  845                 free(adw, M_DEVBUF);
  846                 return NULL;
  847         }
  848         sprintf(adw->name, "adw%d", adw->unit);
  849         return(adw);
  850 }
  851 
  852 void
  853 adw_free(struct adw_softc *adw)
  854 {
  855         switch (adw->init_level) {
  856         case 6:
  857         {
  858                 struct sg_map_node *sg_map;
  859 
  860                 while ((sg_map = SLIST_FIRST(&adw->sg_maps)) != NULL) {
  861                         SLIST_REMOVE_HEAD(&adw->sg_maps, links);
  862                         bus_dmamap_unload(adw->sg_dmat,
  863                                           sg_map->sg_dmamap);
  864                         bus_dmamem_free(adw->sg_dmat, sg_map->sg_vaddr,
  865                                         sg_map->sg_dmamap);
  866                         free(sg_map, M_DEVBUF);
  867                 }
  868                 bus_dma_tag_destroy(adw->sg_dmat);
  869         }
  870         case 5:
  871                 bus_dmamap_unload(adw->acb_dmat, adw->acb_dmamap);
  872         case 4:
  873                 bus_dmamem_free(adw->acb_dmat, adw->acbs,
  874                                 adw->acb_dmamap);
  875                 bus_dmamap_destroy(adw->acb_dmat, adw->acb_dmamap);
  876         case 3:
  877                 bus_dma_tag_destroy(adw->acb_dmat);
  878         case 2:
  879                 bus_dma_tag_destroy(adw->buffer_dmat);
  880         case 1:
  881                 bus_dma_tag_destroy(adw->parent_dmat);
  882         case 0:
  883                 break;
  884         }
  885         free(adw->name, M_DEVBUF);
  886         free(adw, M_DEVBUF);
  887 }
  888 
  889 int
  890 adw_init(struct adw_softc *adw)
  891 {
  892         struct    adw_eeprom eep_config;
  893         u_int16_t checksum;
  894         u_int16_t scsicfg1;
  895 
  896         adw_reset_chip(adw);
  897         checksum = adw_eeprom_read(adw, &eep_config);
  898         bcopy(eep_config.serial_number, adw->serial_number,
  899               sizeof(adw->serial_number));
  900         if (checksum != eep_config.checksum) {
  901                 u_int16_t serial_number[3];
  902 
  903                 printf("%s: EEPROM checksum failed.  Restoring Defaults\n",
  904                        adw_name(adw));
  905 
  906                 /*
  907                  * Restore the default EEPROM settings.
  908                  * Assume the 6 byte board serial number that was read
  909                  * from EEPROM is correct even if the EEPROM checksum
  910                  * failed.
  911                  */
  912                 bcopy(&adw_default_eeprom, &eep_config, sizeof(eep_config));
  913                 bcopy(adw->serial_number, eep_config.serial_number,
  914                       sizeof(serial_number));
  915                 adw_eeprom_write(adw, &eep_config);
  916         }
  917 
  918         /* Pull eeprom information into our softc. */
  919         adw->bios_ctrl = eep_config.bios_ctrl;
  920         adw->user_wdtr = eep_config.wdtr_able;
  921         adw->user_sdtr = eep_config.sdtr_able;
  922         adw->user_ultra = eep_config.ultra_able;
  923         adw->user_tagenb = eep_config.tagqng_able;
  924         adw->user_discenb = eep_config.disc_enable;
  925         adw->max_acbs = eep_config.max_host_qng;
  926         adw->initiator_id = (eep_config.adapter_scsi_id & ADW_MAX_TID);
  927 
  928         /*
  929          * Sanity check the number of host openings.
  930          */
  931         if (adw->max_acbs > ADW_DEF_MAX_HOST_QNG)
  932                 adw->max_acbs = ADW_DEF_MAX_HOST_QNG;
  933         else if (adw->max_acbs < ADW_DEF_MIN_HOST_QNG) {
  934                 /* If the value is zero, assume it is uninitialized. */
  935                 if (adw->max_acbs == 0)
  936                         adw->max_acbs = ADW_DEF_MAX_HOST_QNG;
  937                 else
  938                         adw->max_acbs = ADW_DEF_MIN_HOST_QNG;
  939 
  940         }
  941         
  942         scsicfg1 = 0;
  943         switch (eep_config.termination) {
  944         default:
  945                 printf("%s: Invalid EEPROM Termination Settings.\n",
  946                        adw_name(adw));
  947                 printf("%s: Reverting to Automatic Termination\n",
  948                        adw_name(adw));
  949                 /* FALLTHROUGH */
  950         case ADW_EEPROM_TERM_AUTO:
  951                 break;
  952         case ADW_EEPROM_TERM_BOTH_ON:
  953                 scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_L;
  954                 /* FALLTHROUGH */
  955         case ADW_EEPROM_TERM_HIGH_ON:
  956                 scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_H;
  957                 /* FALLTHROUGH */
  958         case ADW_EEPROM_TERM_OFF:
  959                 scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_MANUAL;
  960                 break;
  961         }
  962 
  963         printf("%s: SCSI ID %d, ", adw_name(adw), adw->initiator_id);
  964 
  965         if (adw_init_chip(adw, scsicfg1) != 0)
  966                 return (-1);
  967 
  968         printf("Queue Depth %d\n", adw->max_acbs);
  969 
  970         /* DMA tag for mapping buffers into device visible space. */
  971         if (bus_dma_tag_create(adw->parent_dmat, /*alignment*/1, /*boundary*/0,
  972                                /*lowaddr*/BUS_SPACE_MAXADDR,
  973                                /*highaddr*/BUS_SPACE_MAXADDR,
  974                                /*filter*/NULL, /*filterarg*/NULL,
  975                                /*maxsize*/MAXBSIZE, /*nsegments*/ADW_SGSIZE,
  976                                /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
  977                                /*flags*/BUS_DMA_ALLOCNOW,
  978                                &adw->buffer_dmat) != 0) {
  979                 return (-1);
  980         }
  981 
  982         adw->init_level++;
  983 
  984         /* DMA tag for our ccb structures */
  985         if (bus_dma_tag_create(adw->parent_dmat, /*alignment*/1, /*boundary*/0,
  986                                /*lowaddr*/BUS_SPACE_MAXADDR,
  987                                /*highaddr*/BUS_SPACE_MAXADDR,
  988                                /*filter*/NULL, /*filterarg*/NULL,
  989                                adw->max_acbs * sizeof(struct acb),
  990                                /*nsegments*/1,
  991                                /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
  992                                /*flags*/0, &adw->acb_dmat) != 0) {
  993                 return (-1);
  994         }
  995 
  996         adw->init_level++;
  997 
  998         /* Allocation for our ccbs */
  999         if (bus_dmamem_alloc(adw->acb_dmat, (void **)&adw->acbs,
 1000                              BUS_DMA_NOWAIT, &adw->acb_dmamap) != 0) {
 1001                 return (-1);
 1002         }
 1003 
 1004         adw->init_level++;
 1005 
 1006         /* And permanently map them */
 1007         bus_dmamap_load(adw->acb_dmat, adw->acb_dmamap,
 1008                         adw->acbs,
 1009                         adw->max_acbs * sizeof(struct acb),
 1010                         adwmapmem, &adw->acb_busbase, /*flags*/0);
 1011 
 1012         /* Clear them out. */
 1013         bzero(adw->acbs, adw->max_acbs * sizeof(struct acb)); 
 1014 
 1015         /* DMA tag for our S/G structures.  We allocate in page sized chunks */
 1016         if (bus_dma_tag_create(adw->parent_dmat, /*alignment*/1, /*boundary*/0,
 1017                                /*lowaddr*/BUS_SPACE_MAXADDR,
 1018                                /*highaddr*/BUS_SPACE_MAXADDR,
 1019                                /*filter*/NULL, /*filterarg*/NULL,
 1020                                PAGE_SIZE, /*nsegments*/1,
 1021                                /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
 1022                                /*flags*/0, &adw->sg_dmat) != 0) {
 1023                 return (-1);
 1024         }
 1025 
 1026         adw->init_level++;
 1027 
 1028         /* Allocate our first batch of ccbs */
 1029         if (adwallocacbs(adw) == 0)
 1030                 return (-1);
 1031 
 1032         return (0);
 1033 }
 1034 
 1035 /*
 1036  * Attach all the sub-devices we can find
 1037  */
 1038 int
 1039 adw_attach(struct adw_softc *adw)
 1040 {
 1041         struct ccb_setasync csa;
 1042         struct cam_devq *devq;
 1043 
 1044         /* Start the Risc processor now that we are fully configured. */
 1045         adw_outw(adw, ADW_RISC_CSR, ADW_RISC_CSR_RUN);
 1046 
 1047         /*
 1048          * Create the device queue for our SIM.
 1049          */
 1050         devq = cam_simq_alloc(adw->max_acbs);
 1051         if (devq == NULL)
 1052                 return (0);
 1053 
 1054         /*
 1055          * Construct our SIM entry.
 1056          */
 1057         adw->sim = cam_sim_alloc(adw_action, adw_poll, "adw", adw, adw->unit,
 1058                                  1, adw->max_acbs, devq);
 1059         if (adw->sim == NULL)
 1060                 return (0);
 1061 
 1062         /*
 1063          * Register the bus.
 1064          */
 1065         if (xpt_bus_register(adw->sim, 0) != CAM_SUCCESS) {
 1066                 cam_sim_free(adw->sim, /*free devq*/TRUE);
 1067                 return (0);
 1068         }
 1069 
 1070         if (xpt_create_path(&adw->path, /*periph*/NULL, cam_sim_path(adw->sim),
 1071                             CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD)
 1072            == CAM_REQ_CMP) {
 1073                 xpt_setup_ccb(&csa.ccb_h, adw->path, /*priority*/5);
 1074                 csa.ccb_h.func_code = XPT_SASYNC_CB;
 1075                 csa.event_enable = AC_LOST_DEVICE;
 1076                 csa.callback = adw_async;
 1077                 csa.callback_arg = adw;
 1078                 xpt_action((union ccb *)&csa);
 1079         }
 1080 
 1081         return (0);
 1082 }
 1083 
 1084 void
 1085 adw_intr(void *arg)
 1086 {
 1087         struct  adw_softc *adw;
 1088         u_int   int_stat;
 1089         u_int   next_doneq;
 1090         u_int   next_completeq;
 1091         u_int   doneq_start;
 1092         
 1093         adw = (struct adw_softc *)arg;
 1094         if ((adw_inw(adw, ADW_CTRL_REG) & ADW_CTRL_REG_HOST_INTR) == 0)
 1095                 return;
 1096 
 1097         /* Reading the register clears the interrupt. */
 1098         int_stat = adw_inb(adw, ADW_INTR_STATUS_REG);
 1099 
 1100         if ((int_stat & ADW_INTR_STATUS_INTRB) != 0) {
 1101                 /* Idle Command Complete */
 1102                 adw->idle_command_cmp = 1;
 1103                 switch (adw->idle_cmd) {
 1104                 case ADW_IDLE_CMD_DEVICE_RESET:
 1105                         adw_handle_device_reset(adw,
 1106                                                 /*target*/adw->idle_cmd_param);
 1107                         break;
 1108                 case ADW_IDLE_CMD_SCSI_RESET:
 1109                         adw_handle_bus_reset(adw, /*initiated*/TRUE);
 1110                         break;
 1111                 default:
 1112                         break;
 1113                 }
 1114                 adw->idle_cmd = ADW_IDLE_CMD_COMPLETED;
 1115         }
 1116 
 1117         if ((int_stat & ADW_INTR_STATUS_INTRC) != 0) {
 1118                 /* SCSI Bus Reset */
 1119                 adw_handle_bus_reset(adw, /*initiated*/FALSE);
 1120         }
 1121 
 1122         /*
 1123          * ADW_MC_HOST_NEXT_DONE is actually the last completed RISC
 1124          * Queue List request. Its forward pointer (RQL_FWD) points to the
 1125          * current completed RISC Queue List request.
 1126          */
 1127         next_doneq = adw_lram_read_8(adw, ADW_MC_HOST_NEXT_DONE);
 1128         next_doneq = ADW_MC_RISC_Q_LIST_BASE + RQL_FWD
 1129                    + (next_doneq * ADW_MC_RISC_Q_LIST_SIZE);
 1130 
 1131         next_completeq = adw_lram_read_8(adw, next_doneq);
 1132         doneq_start = ADW_MC_NULL_Q;
 1133         /* Loop until all completed Q's are processed. */
 1134         while (next_completeq != ADW_MC_NULL_Q) {
 1135                 u_int32_t acb_busaddr;
 1136                 struct    acb *acb;
 1137                 union     ccb *ccb;
 1138 
 1139                 doneq_start = next_completeq;
 1140 
 1141                 next_doneq = ADW_MC_RISC_Q_LIST_BASE +
 1142                              (next_completeq * ADW_MC_RISC_Q_LIST_SIZE);
 1143 
 1144                 /*
 1145                  * Read the ADW_SCSI_REQ_Q physical address pointer from
 1146                  * the RISC list entry.
 1147                  */
 1148                 acb_busaddr = adw_lram_read_32(adw, next_doneq + RQL_PHYADDR);
 1149                 acb = acbptov(adw, acb_busaddr);
 1150                 
 1151                 /* Change the RISC Queue List state to free. */
 1152                 adw_lram_write_8(adw, next_doneq + RQL_STATE, ADW_MC_QS_FREE);
 1153 
 1154                 /* Get the RISC Queue List forward pointer. */
 1155                 next_completeq = adw_lram_read_8(adw, next_doneq + RQL_FWD);
 1156 
 1157                 /* Process CCB */
 1158                 ccb = acb->ccb;
 1159                 untimeout(adwtimeout, acb, ccb->ccb_h.timeout_ch);
 1160                 if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
 1161                         bus_dmasync_op_t op;
 1162 
 1163                         if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
 1164                                 op = BUS_DMASYNC_POSTREAD;
 1165                         else
 1166                                 op = BUS_DMASYNC_POSTWRITE;
 1167                         bus_dmamap_sync(adw->buffer_dmat, acb->dmamap, op);
 1168                         bus_dmamap_unload(adw->buffer_dmat, acb->dmamap);
 1169                         ccb->csio.resid = acb->queue.data_cnt;
 1170                 } else 
 1171                         ccb->csio.resid = 0;
 1172 
 1173                 /* Common Cases inline... */
 1174                 if (acb->queue.host_status == QHSTA_NO_ERROR
 1175                  && (acb->queue.done_status == QD_NO_ERROR
 1176                   || acb->queue.done_status == QD_WITH_ERROR)) {
 1177                         ccb->csio.scsi_status = acb->queue.scsi_status;
 1178                         ccb->ccb_h.status = 0;
 1179                         switch (ccb->csio.scsi_status) {
 1180                         case SCSI_STATUS_OK:
 1181                                 ccb->ccb_h.status |= CAM_REQ_CMP;
 1182                                 break;
 1183                         case SCSI_STATUS_CHECK_COND:
 1184                         case SCSI_STATUS_CMD_TERMINATED:
 1185                                 bcopy(&acb->sense_data, &ccb->csio.sense_data,
 1186                                       ccb->csio.sense_len);
 1187                                 ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
 1188                                 ccb->csio.sense_resid = acb->queue.sense_len;
 1189                                 /* FALLTHROUGH */
 1190                         default:
 1191                                 ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR
 1192                                                   |  CAM_DEV_QFRZN;
 1193                                 xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
 1194                                 break;
 1195                         }
 1196                         adwfreeacb(adw, acb);
 1197                         xpt_done(ccb);
 1198 
 1199                 } else {
 1200                         adwprocesserror(adw, acb);
 1201                 }
 1202         }
 1203 
 1204         if (doneq_start != ADW_MC_NULL_Q)
 1205                 adw_lram_write_8(adw, ADW_MC_HOST_NEXT_DONE, doneq_start);
 1206 }
 1207 
 1208 static void
 1209 adwprocesserror(struct adw_softc *adw, struct acb *acb)
 1210 {
 1211         union ccb *ccb;
 1212 
 1213         ccb = acb->ccb;
 1214         if (acb->queue.done_status == QD_ABORTED_BY_HOST) {
 1215                 ccb->ccb_h.status = CAM_REQ_ABORTED;
 1216         } else {
 1217 
 1218                 switch (acb->queue.host_status) {
 1219                 case QHSTA_M_SEL_TIMEOUT:
 1220                         ccb->ccb_h.status = CAM_SEL_TIMEOUT;
 1221                         break;
 1222                 case QHSTA_M_SXFR_OFF_UFLW:
 1223                 case QHSTA_M_SXFR_OFF_OFLW:
 1224                 case QHSTA_M_DATA_OVER_RUN:
 1225                         ccb->ccb_h.status = CAM_DATA_RUN_ERR;
 1226                         break;
 1227                 case QHSTA_M_SXFR_DESELECTED:
 1228                 case QHSTA_M_UNEXPECTED_BUS_FREE:
 1229                         ccb->ccb_h.status = CAM_UNEXP_BUSFREE;
 1230                         break;
 1231                 case QHSTA_M_QUEUE_ABORTED:
 1232                         /* BDR or Bus Reset */
 1233                         ccb->ccb_h.status = adw->last_reset;
 1234                         break;
 1235                 case QHSTA_M_SXFR_SDMA_ERR:
 1236                 case QHSTA_M_SXFR_SXFR_PERR:
 1237                 case QHSTA_M_RDMA_PERR:
 1238                         ccb->ccb_h.status = CAM_UNCOR_PARITY;
 1239                         break;
 1240                 case QHSTA_M_WTM_TIMEOUT:
 1241                 case QHSTA_M_SXFR_WD_TMO:
 1242                         /* The SCSI bus hung in a phase */
 1243                         ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
 1244                         adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET,
 1245                                           /*param*/0);
 1246                         break;
 1247                 case QHSTA_M_SXFR_XFR_PH_ERR:
 1248                         ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
 1249                         break;
 1250                 case QHSTA_M_SXFR_UNKNOWN_ERROR:
 1251                         break;
 1252                 case QHSTA_M_BAD_CMPL_STATUS_IN:
 1253                         /* No command complete after a status message */
 1254                         ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
 1255                         break;
 1256                 case QHSTA_M_AUTO_REQ_SENSE_FAIL:
 1257                         ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
 1258                         break;
 1259                 case QHSTA_M_INVALID_DEVICE:
 1260                         ccb->ccb_h.status = CAM_PATH_INVALID;
 1261                         break;
 1262                 case QHSTA_M_NO_AUTO_REQ_SENSE:
 1263                         /*
 1264                          * User didn't request sense, but we got a
 1265                          * check condition.
 1266                          */
 1267                         ccb->csio.scsi_status = acb->queue.scsi_status;
 1268                         ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
 1269                         break;
 1270                 default:
 1271                         panic("%s: Unhandled Host status error %x",
 1272                               adw_name(adw), acb->queue.host_status);
 1273                         /* NOTREACHED */
 1274                 }
 1275         }
 1276         if (ccb->ccb_h.status != CAM_REQ_CMP) {
 1277                 xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
 1278                 ccb->ccb_h.status |= CAM_DEV_QFRZN;
 1279         }
 1280         adwfreeacb(adw, acb);
 1281         xpt_done(ccb);
 1282 }
 1283 
 1284 static void
 1285 adwtimeout(void *arg)
 1286 {
 1287         struct acb           *acb;
 1288         union  ccb           *ccb;
 1289         struct adw_softc     *adw;
 1290         adw_idle_cmd_status_t status;
 1291         int                   s;
 1292 
 1293         acb = (struct acb *)arg;
 1294         ccb = acb->ccb;
 1295         adw = (struct adw_softc *)ccb->ccb_h.ccb_adw_ptr;
 1296         xpt_print_path(ccb->ccb_h.path);
 1297         printf("ACB %p - timed out\n", (void *)acb);
 1298 
 1299         s = splcam();
 1300 
 1301         if ((acb->state & ACB_ACTIVE) == 0) {
 1302                 xpt_print_path(ccb->ccb_h.path);
 1303                 printf("ACB %p - timed out CCB already completed\n",
 1304                        (void *)acb);
 1305                 splx(s);
 1306                 return;
 1307         }
 1308 
 1309         /* Attempt a BDR first */
 1310         adw_idle_cmd_send(adw, ADW_IDLE_CMD_DEVICE_RESET,
 1311                           ccb->ccb_h.target_id);
 1312         splx(s);
 1313         status = adw_idle_cmd_wait(adw);
 1314         if (status == ADW_IDLE_CMD_SUCCESS) {
 1315                 printf("%s: BDR Delivered.  No longer in timeout\n",
 1316                        adw_name(adw));
 1317         } else {
 1318                 adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET, /*param*/0);
 1319                 status = adw_idle_cmd_wait(adw);
 1320                 if (status != ADW_IDLE_CMD_SUCCESS)
 1321                         panic("%s: Bus Reset during timeout failed",
 1322                               adw_name(adw));
 1323         }
 1324 }
 1325 
 1326 static void
 1327 adw_handle_device_reset(struct adw_softc *adw, u_int target)
 1328 {
 1329         struct cam_path *path;
 1330         cam_status error;
 1331 
 1332         error = xpt_create_path(&path, /*periph*/NULL, cam_sim_path(adw->sim),
 1333                                 target, CAM_LUN_WILDCARD);
 1334 
 1335         if (error == CAM_REQ_CMP) {
 1336                 xpt_async(AC_SENT_BDR, path, NULL);
 1337                 xpt_free_path(path);
 1338         }
 1339         adw->last_reset = CAM_BDR_SENT;
 1340 }
 1341 
 1342 static void
 1343 adw_handle_bus_reset(struct adw_softc *adw, int initiated)
 1344 {
 1345         if (initiated) {
 1346                 /*
 1347                  * The microcode currently sets the SCSI Bus Reset signal
 1348                  * while handling the AscSendIdleCmd() IDLE_CMD_SCSI_RESET
 1349                  * command above.  But the SCSI Bus Reset Hold Time in the
 1350                  * microcode is not deterministic (it may in fact be for less
 1351                  * than the SCSI Spec. minimum of 25 us).  Therefore on return
 1352                  * the Adv Library sets the SCSI Bus Reset signal for
 1353                  * ADW_SCSI_RESET_HOLD_TIME_US, which is defined to be greater
 1354                  * than 25 us.
 1355                  */
 1356                 u_int scsi_ctrl;
 1357 
 1358                 scsi_ctrl = adw_inw(adw, ADW_SCSI_CTRL) & ~ADW_SCSI_CTRL_RSTOUT;
 1359                 adw_outw(adw, ADW_SCSI_CTRL, scsi_ctrl | ADW_SCSI_CTRL_RSTOUT);
 1360                 DELAY(ADW_SCSI_RESET_HOLD_TIME_US);
 1361                 adw_outw(adw, ADW_SCSI_CTRL, scsi_ctrl);
 1362 
 1363                 /*
 1364                  * We will perform the async notification when the
 1365                  * SCSI Reset interrupt occurs.
 1366                  */
 1367         } else
 1368                 xpt_async(AC_BUS_RESET, adw->path, NULL);
 1369         adw->last_reset = CAM_SCSI_BUS_RESET;
 1370 }

Cache object: 378b1db7eda8c7cc1be7e2ae7210c1a1


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