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/i386/eisa/ahb.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 device driver for the Adaptec 174X SCSI Host adapter
    3  *
    4  * Copyright (c) 1998 Justin T. Gibbs
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice immediately at the beginning of the file, without modification,
   12  *    this list of conditions, and the following disclaimer.
   13  * 2. The name of the author may not be used to endorse or promote products
   14  *    derived from this software without specific prior written permission.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  *
   28  * $FreeBSD$
   29  */
   30 
   31 #include "eisa.h"
   32 #if NEISA > 0
   33 #include <stddef.h>     /* For offsetof() */
   34 
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/kernel.h>
   38 #include <sys/malloc.h>
   39 
   40 #include <machine/bus_pio.h>
   41 #include <machine/bus.h>
   42 #include <machine/clock.h>
   43 
   44 #include <cam/cam.h>
   45 #include <cam/cam_ccb.h>
   46 #include <cam/cam_sim.h>
   47 #include <cam/cam_xpt_sim.h>
   48 #include <cam/cam_debug.h>
   49 
   50 #include <cam/scsi/scsi_message.h>
   51 
   52 #include <i386/eisa/eisaconf.h>
   53 
   54 #include <i386/eisa/ahbreg.h>
   55 
   56 #define ccb_ecb_ptr spriv_ptr0
   57 #define ccb_ahb_ptr spriv_ptr1
   58 
   59 #define MIN(a, b) ((a) < (b) ? (a) : (b))
   60 
   61 #define ahb_inb(ahb, port)                              \
   62         bus_space_read_1((ahb)->tag, (ahb)->bsh, port)
   63 
   64 #define ahb_inl(ahb, port)                              \
   65         bus_space_read_4((ahb)->tag, (ahb)->bsh, port)
   66 
   67 #define ahb_outb(ahb, port, value)                      \
   68         bus_space_write_1((ahb)->tag, (ahb)->bsh, port, value)
   69 
   70 #define ahb_outl(ahb, port, value)                      \
   71         bus_space_write_4((ahb)->tag, (ahb)->bsh, port, value)
   72 
   73 static const char               *ahbmatch(eisa_id_t type);
   74 static int                       ahbprobe(void);
   75 static int                       ahbattach(struct eisa_device *dev);
   76 static struct ahb_softc         *ahballoc(u_long unit, u_int iobase, u_int irq);
   77 static void                      ahbfree(struct ahb_softc *ahb);
   78 static int                       ahbreset(struct ahb_softc *ahb);
   79 static void                      ahbmapecbs(void *arg, bus_dma_segment_t *segs,
   80                                             int nseg, int error);
   81 static int                       ahbxptattach(struct ahb_softc *ahb);
   82 static void                      ahbhandleimmed(struct ahb_softc *ahb,
   83                                                 u_int32_t mbox, u_int intstat);
   84 static void                      ahbcalcresid(struct ahb_softc *ahb,
   85                                               struct ecb *ecb, union ccb *ccb);
   86 static __inline void             ahbdone(struct ahb_softc *ahb, u_int32_t mbox,
   87                                          u_int intstat);
   88 static void                      ahbintr(void *arg);
   89 static bus_dmamap_callback_t     ahbexecuteecb;
   90 static void                      ahbaction(struct cam_sim *sim, union ccb *ccb);
   91 static void                      ahbpoll(struct cam_sim *sim);
   92 
   93 /* Our timeout handler */
   94 timeout_t ahbtimeout;
   95 
   96 static __inline struct ecb*     ahbecbget(struct ahb_softc *ahb);
   97 static __inline void            ahbecbfree(struct ahb_softc* ahb,
   98                                            struct ecb* ecb);
   99 static __inline u_int32_t       ahbecbvtop(struct ahb_softc *ahb,
  100                                            struct ecb *ecb);
  101 static __inline struct ecb*     ahbecbptov(struct ahb_softc *ahb,
  102                                            u_int32_t ecb_addr);
  103 static __inline u_int32_t       ahbstatuspaddr(u_int32_t ecb_paddr);
  104 static __inline u_int32_t       ahbsensepaddr(u_int32_t ecb_paddr);
  105 static __inline u_int32_t       ahbsgpaddr(u_int32_t ecb_paddr);
  106 static __inline void            ahbqueuembox(struct ahb_softc *ahb,
  107                                              u_int32_t mboxval,
  108                                              u_int attn_code);
  109 
  110 static __inline struct ecb*
  111 ahbecbget(struct ahb_softc *ahb)
  112 {
  113         struct  ecb* ecb;
  114         int     s;
  115 
  116         s = splcam();
  117         if ((ecb = SLIST_FIRST(&ahb->free_ecbs)) != NULL)
  118                 SLIST_REMOVE_HEAD(&ahb->free_ecbs, links);
  119         splx(s);
  120 
  121         return (ecb);
  122 }
  123 
  124 static __inline void
  125 ahbecbfree(struct ahb_softc* ahb, struct ecb* ecb)
  126 {
  127         int s;
  128 
  129         s = splcam();
  130         ecb->state = ECB_FREE;
  131         SLIST_INSERT_HEAD(&ahb->free_ecbs, ecb, links);
  132         splx(s);
  133 }
  134 
  135 static __inline u_int32_t
  136 ahbecbvtop(struct ahb_softc *ahb, struct ecb *ecb)
  137 {
  138         return (ahb->ecb_physbase
  139               + (u_int32_t)((caddr_t)ecb - (caddr_t)ahb->ecb_array));
  140 }
  141 
  142 static __inline struct ecb*
  143 ahbecbptov(struct ahb_softc *ahb, u_int32_t ecb_addr)
  144 {
  145         return (ahb->ecb_array
  146               + ((struct ecb*)ecb_addr - (struct ecb*)ahb->ecb_physbase));
  147 }
  148 
  149 static __inline u_int32_t
  150 ahbstatuspaddr(u_int32_t ecb_paddr)
  151 {
  152         return (ecb_paddr + offsetof(struct ecb, status));
  153 }
  154 
  155 static __inline u_int32_t
  156 ahbsensepaddr(u_int32_t ecb_paddr)
  157 {
  158         return (ecb_paddr + offsetof(struct ecb, sense));
  159 }
  160 
  161 static __inline u_int32_t
  162 ahbsgpaddr(u_int32_t ecb_paddr)
  163 {
  164         return (ecb_paddr + offsetof(struct ecb, sg_list));
  165 }
  166 
  167 static __inline void
  168 ahbqueuembox(struct ahb_softc *ahb, u_int32_t mboxval, u_int attn_code)
  169 {
  170         u_int loopmax = 300;
  171         while (--loopmax) {
  172                 u_int status;
  173 
  174                 status = ahb_inb(ahb, HOSTSTAT);
  175                 if ((status & (HOSTSTAT_MBOX_EMPTY|HOSTSTAT_BUSY))
  176                    == HOSTSTAT_MBOX_EMPTY)
  177                         break;
  178                 DELAY(20);
  179         }
  180         if (loopmax == 0)
  181                 panic("ahb%ld: adapter not taking commands\n", ahb->unit);
  182 
  183         ahb_outl(ahb, MBOXOUT0, mboxval);
  184         ahb_outb(ahb, ATTN, attn_code);
  185 }
  186 
  187 static  u_long ahbunit;
  188 
  189 static struct eisa_driver ahb_eisa_driver =
  190 {
  191         "ahb",
  192         ahbprobe,
  193         ahbattach,
  194         /*shutdown*/NULL,
  195         &ahbunit
  196 };
  197 
  198 DATA_SET (eisadriver_set, ahb_eisa_driver);
  199 
  200 static const char *
  201 ahbmatch(eisa_id_t type)
  202 {                         
  203         switch(type & 0xfffffe00) {
  204                 case EISA_DEVICE_ID_ADAPTEC_1740:
  205                         return ("Adaptec 174x SCSI host adapter");
  206                         break;
  207                 default:
  208                         break;
  209         }
  210         return (NULL);
  211 } 
  212 
  213 static int
  214 ahbprobe(void)      
  215 {       
  216         struct eisa_device *e_dev = NULL;
  217         u_int32_t iobase;
  218         u_int32_t irq;
  219         int count;      
  220                 
  221         count = 0;      
  222         while ((e_dev = eisa_match_dev(e_dev, ahbmatch))) {
  223                 u_int8_t  intdef;      
  224 
  225                 iobase = (e_dev->ioconf.slot * EISA_SLOT_SIZE) +
  226                          AHB_EISA_SLOT_OFFSET;
  227                         
  228                 eisa_add_iospace(e_dev, iobase, AHB_EISA_IOSIZE, RESVADDR_NONE);
  229                 
  230                 intdef = inb(INTDEF + iobase);
  231                 switch (intdef & 0x7) {
  232                 case INT9:  
  233                         irq = 9;
  234                         break;
  235                 case INT10: 
  236                         irq = 10;
  237                         break;
  238                 case INT11:
  239                         irq = 11;
  240                         break;
  241                 case INT12:
  242                         irq = 12; 
  243                         break;
  244                 case INT14:
  245                         irq = 14;
  246                         break;
  247                 case INT15:
  248                         irq = 15;
  249                         break;
  250                 default:
  251                         printf("Adaptec 174X at slot %d: illegal "
  252                                "irq setting %d\n", e_dev->ioconf.slot,
  253                                (intdef & 0x7));
  254                         irq = 0;
  255                         break;
  256                 }               
  257                 if (irq == 0)
  258                         continue;
  259                 eisa_add_intr(e_dev, irq);
  260                 eisa_registerdev(e_dev, &ahb_eisa_driver);
  261                 count++;        
  262         }               
  263         return count;   
  264 }
  265 
  266 static int
  267 ahbattach(struct eisa_device *e_dev)
  268 {
  269         /*
  270          * find unit and check we have that many defined
  271          */
  272         struct      ahb_softc *ahb;
  273         struct      ecb* next_ecb;
  274         resvaddr_t *iospace;
  275         u_int       irq;
  276 
  277         if (TAILQ_FIRST(&e_dev->ioconf.irqs) == NULL)
  278                 return (-1);
  279 
  280         irq = TAILQ_FIRST(&e_dev->ioconf.irqs)->irq_no;
  281 
  282         iospace = e_dev->ioconf.ioaddrs.lh_first;
  283 
  284         if (iospace == NULL)
  285                 return (-1);
  286 
  287         eisa_reg_start(e_dev);
  288         if (eisa_reg_iospace(e_dev, iospace)) {
  289                 eisa_reg_end(e_dev);
  290                 return (-1);
  291         }
  292 
  293         if ((ahb = ahballoc(e_dev->unit, iospace->addr, irq)) == NULL) {
  294                 eisa_reg_end(e_dev);
  295                 return (-1);
  296         }
  297 
  298         if (ahbreset(ahb) != 0)
  299                 return (-1);
  300 
  301         if (eisa_reg_intr(e_dev, irq, ahbintr, (void *)ahb, &cam_imask,
  302                           (ahb_inb(ahb, INTDEF) & INTLEVEL) ? TRUE : FALSE)) {
  303                 eisa_reg_end(e_dev);
  304                 ahbfree(ahb);
  305                 return (-1);
  306         }
  307 
  308         /*
  309          * Create our DMA tags.  These tags define the kinds of device
  310          * accessable memory allocations and memory mappings we will 
  311          * need to perform during normal operation.
  312          */
  313         /* DMA tag for mapping buffers into device visible space. */
  314         /* XXX Should be a child of the EISA bus dma tag */
  315         if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/1, /*boundary*/0,
  316                                /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
  317                                /*highaddr*/BUS_SPACE_MAXADDR,
  318                                /*filter*/NULL, /*filterarg*/NULL,
  319                                /*maxsize*/MAXBSIZE, /*nsegments*/AHB_NSEG,
  320                                /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
  321                                /*flags*/BUS_DMA_ALLOCNOW,
  322                                &ahb->buffer_dmat) != 0)
  323                 goto error_exit;
  324 
  325         ahb->init_level++;
  326 
  327         /* DMA tag for our ccb structures and ha inquiry data */
  328         if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/1, /*boundary*/0,
  329                                /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
  330                                /*highaddr*/BUS_SPACE_MAXADDR,
  331                                /*filter*/NULL, /*filterarg*/NULL,
  332                                (AHB_NECB * sizeof(struct ecb))
  333                                + sizeof(*ahb->ha_inq_data),
  334                                /*nsegments*/1,
  335                                /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
  336                                /*flags*/0, &ahb->ecb_dmat) != 0)
  337                 goto error_exit;
  338 
  339         ahb->init_level++;
  340 
  341         /* Allocation for our ccbs */
  342         if (bus_dmamem_alloc(ahb->ecb_dmat, (void **)&ahb->ecb_array,
  343                              BUS_DMA_NOWAIT, &ahb->ecb_dmamap) != 0)
  344                 goto error_exit;
  345 
  346         ahb->ha_inq_data = (struct ha_inquiry_data *)&ahb->ecb_array[AHB_NECB];
  347 
  348         ahb->init_level++;
  349 
  350         /* And permanently map them */
  351         bus_dmamap_load(ahb->ecb_dmat, ahb->ecb_dmamap,
  352                         ahb->ecb_array, AHB_NSEG * sizeof(struct ecb),
  353                         ahbmapecbs, ahb, /*flags*/0);
  354 
  355         ahb->init_level++;
  356 
  357         /* Allocate the buffer dmamaps for each of our ECBs */
  358         bzero(ahb->ecb_array, (AHB_NECB * sizeof(struct ecb))
  359               + sizeof(*ahb->ha_inq_data));
  360         next_ecb = ahb->ecb_array;
  361         while (ahb->num_ecbs < AHB_NECB) {
  362                 u_int32_t ecb_paddr;
  363 
  364                 if (bus_dmamap_create(ahb->buffer_dmat, /*flags*/0,
  365                                       &next_ecb->dmamap))
  366                         break;
  367                 ecb_paddr = ahbecbvtop(ahb, next_ecb);
  368                 next_ecb->hecb.status_ptr = ahbstatuspaddr(ecb_paddr);
  369                 next_ecb->hecb.sense_ptr = ahbsensepaddr(ecb_paddr);
  370                 ahb->num_ecbs++;
  371                 ahbecbfree(ahb, next_ecb);
  372                 next_ecb++;
  373         }
  374 
  375         if (ahb->num_ecbs == 0)
  376                 goto error_exit;
  377 
  378         ahb->init_level++;
  379 
  380         eisa_reg_end(e_dev);
  381 
  382         /*
  383          * Now that we know we own the resources we need, register
  384          * our bus with the XPT.
  385          */
  386         if (ahbxptattach(ahb))
  387                 goto error_exit;
  388 
  389         /* Enable our interrupt */
  390         eisa_enable_intr(e_dev, irq);
  391         return (0);
  392 error_exit:
  393         /*
  394          * The board's IRQ line will not be left enabled
  395          * if we can't intialize correctly, so its safe
  396          * to release the irq.
  397          */
  398         eisa_release_intr(e_dev, irq, ahbintr);
  399         ahbfree(ahb);
  400         return (-1);
  401 }
  402 
  403 static struct ahb_softc *
  404 ahballoc(u_long unit,  u_int iobase, u_int irq)
  405 {
  406         struct  ahb_softc *ahb;
  407 
  408         /*
  409          * Allocate a storage area for us
  410          */
  411         ahb = malloc(sizeof(struct ahb_softc), M_TEMP, M_NOWAIT);
  412         if (!ahb) {
  413                 printf("ahb%ld: cannot malloc!\n", unit);
  414                 return (NULL);
  415         }
  416         bzero(ahb, sizeof(struct ahb_softc));
  417         SLIST_INIT(&ahb->free_ecbs);
  418         LIST_INIT(&ahb->pending_ccbs);
  419         ahb->unit = unit;
  420         ahb->tag = I386_BUS_SPACE_IO;
  421         ahb->bsh = iobase;
  422         ahb->disc_permitted = ~0;
  423         ahb->tags_permitted = ~0;
  424 
  425         return (ahb);
  426 }
  427 
  428 static void    
  429 ahbfree(struct ahb_softc *ahb)
  430 {
  431         switch (ahb->init_level) {
  432         default:
  433         case 4:
  434                 bus_dmamap_unload(ahb->ecb_dmat, ahb->ecb_dmamap);
  435         case 3:
  436                 bus_dmamem_free(ahb->ecb_dmat, ahb->ecb_array,
  437                                 ahb->ecb_dmamap);
  438                 bus_dmamap_destroy(ahb->ecb_dmat, ahb->ecb_dmamap);
  439         case 2:
  440                 bus_dma_tag_destroy(ahb->ecb_dmat);
  441         case 1:
  442                 bus_dma_tag_destroy(ahb->buffer_dmat);
  443         case 0:
  444         }
  445         free(ahb, M_DEVBUF);
  446 }
  447 
  448 /*
  449  * reset board, If it doesn't respond, return failure
  450  */
  451 static int
  452 ahbreset(struct ahb_softc *ahb)
  453 {
  454         int     wait = 1000;    /* 1 sec enough? */
  455         int     test;
  456 
  457         if ((ahb_inb(ahb, PORTADDR) & PORTADDR_ENHANCED) == 0) {
  458                 printf("ahb_reset: Controller not in enhanced mode\n");
  459                 return (-1);
  460         }
  461 
  462         ahb_outb(ahb, CONTROL, CNTRL_HARD_RST);
  463         DELAY(1000);
  464         ahb_outb(ahb, CONTROL, 0);
  465         while (--wait) {
  466                 DELAY(1000);
  467                 if ((ahb_inb(ahb, HOSTSTAT) & HOSTSTAT_BUSY) == 0)
  468                         break;
  469         }
  470 
  471         if (wait == 0) {
  472                 printf("ahbreset: No answer from aha1742 board\n");
  473                 return (-1);
  474         }
  475         if ((test = ahb_inb(ahb, MBOXIN0)) != 0) {
  476                 printf("ahb_reset: self test failed, val = 0x%x\n", test);
  477                 return (-1);
  478         }
  479         while (ahb_inb(ahb, HOSTSTAT) & HOSTSTAT_INTPEND) {
  480                 ahb_outb(ahb, CONTROL, CNTRL_CLRINT);
  481                 DELAY(10000);
  482         }
  483         return (0);
  484 }
  485 
  486 static void
  487 ahbmapecbs(void *arg, bus_dma_segment_t *segs, int nseg, int error)
  488 {
  489         struct ahb_softc* ahb;
  490 
  491         ahb = (struct ahb_softc*)arg;
  492         ahb->ecb_physbase = segs->ds_addr;
  493         /*
  494          * Space for adapter inquiry information is on the
  495          * tail of the ecb array.
  496          */
  497         ahb->ha_inq_physbase = ahbecbvtop(ahb, &ahb->ecb_array[AHB_NECB]);
  498 }
  499 
  500 static int
  501 ahbxptattach(struct ahb_softc *ahb)
  502 {
  503         struct cam_devq *devq;
  504         struct ecb *ecb;
  505         u_int  i;
  506 
  507         /* Remeber who are we on the scsi bus */
  508         ahb->scsi_id = ahb_inb(ahb, SCSIDEF) & HSCSIID;
  509 
  510         /* Use extended translation?? */
  511         ahb->extended_trans = ahb_inb(ahb, RESV1) & EXTENDED_TRANS;
  512 
  513         /* Fetch adapter inquiry data */
  514         ecb = ahbecbget(ahb);   /* Always succeeds - no outstanding commands */
  515         ecb->hecb.opcode = ECBOP_READ_HA_INQDATA;
  516         ecb->hecb.flag_word1 = FW1_SUPPRESS_URUN_ERR|FW1_ERR_STATUS_BLK_ONLY;
  517         ecb->hecb.data_ptr = ahb->ha_inq_physbase;
  518         ecb->hecb.data_len = sizeof(struct ha_inquiry_data);
  519         ecb->hecb.sense_ptr = 0;
  520         ecb->state = ECB_ACTIVE;
  521         
  522         /* Tell the adapter about this command */
  523         ahbqueuembox(ahb, ahbecbvtop(ahb, ecb),
  524                      ATTN_STARTECB|ahb->scsi_id);
  525 
  526         /* Poll for interrupt completion */
  527         for (i = 1000; ecb->state != ECB_FREE && i != 0; i--) {
  528                 ahbintr(ahb);
  529                 DELAY(1000);
  530         }
  531 
  532         ahb->num_ecbs = MIN(ahb->num_ecbs,
  533                             ahb->ha_inq_data->scsi_data.reserved[1]);
  534         printf("ahb%ld: %.8s %s SCSI Adapter, FW Rev. %.4s, ID=%d, %d ECBs\n",
  535                ahb->unit, ahb->ha_inq_data->scsi_data.product,
  536                (ahb->ha_inq_data->scsi_data.flags & 0x4) ? "Differential"
  537                                                          : "Single Ended",
  538                ahb->ha_inq_data->scsi_data.revision,
  539                ahb->scsi_id, ahb->num_ecbs);
  540 
  541         /* Restore sense paddr for future CCB clients */
  542         ecb->hecb.sense_ptr = ahbsensepaddr(ahbecbvtop(ahb, ecb));
  543 
  544         ahbecbfree(ahb, ecb);
  545 
  546         /*
  547          * Create the device queue for our SIM.
  548          */
  549         devq = cam_simq_alloc(ahb->num_ecbs);
  550         if (devq == NULL)
  551                 return (ENOMEM);
  552 
  553         /*
  554          * Construct our SIM entry
  555          */
  556         ahb->sim = cam_sim_alloc(ahbaction, ahbpoll, "ahb", ahb, ahb->unit,
  557                                  2, ahb->num_ecbs, devq);
  558         if (ahb->sim == NULL) {
  559                 cam_simq_free(devq);
  560                 return (ENOMEM);
  561         }
  562 
  563         if (xpt_bus_register(ahb->sim, 0) != CAM_SUCCESS) {
  564                 cam_sim_free(ahb->sim, /*free_devq*/TRUE);
  565                 return (ENXIO);
  566         }
  567         
  568         if (xpt_create_path(&ahb->path, /*periph*/NULL,
  569                             cam_sim_path(ahb->sim), CAM_TARGET_WILDCARD,
  570                             CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
  571                 xpt_bus_deregister(cam_sim_path(ahb->sim));
  572                 cam_sim_free(ahb->sim, /*free_devq*/TRUE);
  573                 return (ENXIO);
  574         }
  575                 
  576         /*
  577          * Allow the board to generate interrupts.
  578          */
  579         ahb_outb(ahb, INTDEF, ahb_inb(ahb, INTDEF) | INTEN);
  580 
  581         return (0);
  582 }
  583 
  584 static void
  585 ahbhandleimmed(struct ahb_softc *ahb, u_int32_t mbox, u_int intstat)
  586 {
  587         struct ccb_hdr *ccb_h;
  588         u_int target_id;
  589 
  590         if (ahb->immed_cmd == 0) {
  591                 printf("ahb%ld: Immediate Command complete with no "
  592                        " pending command\n", ahb->unit);
  593                 return;
  594         }
  595 
  596         target_id = intstat & INTSTAT_TARGET_MASK;
  597 
  598         ccb_h = LIST_FIRST(&ahb->pending_ccbs);
  599         while (ccb_h != NULL) {
  600                 struct ecb *pending_ecb;
  601                 union ccb *ccb;
  602 
  603                 pending_ecb = (struct ecb *)ccb_h->ccb_ecb_ptr;
  604                 ccb = pending_ecb->ccb;
  605                 ccb_h = LIST_NEXT(ccb_h, sim_links.le);
  606                 if (ccb->ccb_h.target_id == target_id
  607                  || target_id == ahb->scsi_id) {
  608                         untimeout(ahbtimeout, pending_ecb,
  609                                   ccb->ccb_h.timeout_ch);
  610                         LIST_REMOVE(&ccb->ccb_h, sim_links.le);
  611                         if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)
  612                                 bus_dmamap_unload(ahb->buffer_dmat,
  613                                                   pending_ecb->dmamap);
  614                         if (pending_ecb == ahb->immed_ecb)
  615                                 ccb->ccb_h.status =
  616                                     CAM_CMD_TIMEOUT|CAM_RELEASE_SIMQ;
  617                         else if (target_id == ahb->scsi_id)
  618                                 ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
  619                         else
  620                                 ccb->ccb_h.status = CAM_BDR_SENT;
  621                         ahbecbfree(ahb, pending_ecb);
  622                         xpt_done(ccb);
  623                 } else if (ahb->immed_ecb != NULL) {
  624                         /* Re-instate timeout */
  625                         ccb->ccb_h.timeout_ch =
  626                             timeout(ahbtimeout, (caddr_t)pending_ecb,
  627                                     (ccb->ccb_h.timeout * hz) / 1000);
  628                 }
  629         }
  630 
  631         if (ahb->immed_ecb != NULL) {
  632                 ahb->immed_ecb = NULL;
  633                 printf("ahb%ld: No longer in timeout\n", ahb->unit);
  634         } else if (target_id == ahb->scsi_id)
  635                 printf("ahb%ld: SCSI Bus Reset Delivered\n", ahb->unit);
  636         else
  637                 printf("ahb%ld:  Bus Device Reset Delibered to target %d\n",
  638                        ahb->unit, target_id);
  639 
  640         ahb->immed_cmd = 0;
  641 }
  642 
  643 static void
  644 ahbcalcresid(struct ahb_softc *ahb, struct ecb *ecb, union ccb *ccb)
  645 {
  646         if (ecb->status.data_overrun != 0) {
  647                 /*
  648                  * Overrun Condition.  The hardware doesn't
  649                  * provide a meaningful byte count in this case
  650                  * (the residual is always 0).  Tell the XPT
  651                  * layer about the error.
  652                  */
  653                 ccb->ccb_h.status = CAM_DATA_RUN_ERR;
  654         } else {
  655                 ccb->csio.resid = ecb->status.resid_count;
  656 
  657                 if ((ecb->hecb.flag_word1 & FW1_SG_ECB) != 0) {
  658                         /*
  659                          * For S/G transfers, the adapter provides a pointer
  660                          * to the address in the last S/G element used and a
  661                          * residual for that element.  So, we need to sum up
  662                          * the elements that follow it in order to get a real
  663                          * residual number.  If we have an overrun, the residual
  664                          * reported will be 0 and we already know that all S/G
  665                          * segments have been exhausted, so we can skip this
  666                          * step.
  667                          */
  668                         ahb_sg_t *sg;
  669                         int       num_sg;
  670 
  671                         num_sg = ecb->hecb.data_len / sizeof(ahb_sg_t);
  672 
  673                         /* Find the S/G the adapter was working on */
  674                         for (sg = ecb->sg_list;
  675                              num_sg != 0 && sg->addr != ecb->status.resid_addr;
  676                              num_sg--, sg++)
  677                                 ;
  678 
  679                         /* Skip it */
  680                         num_sg--;
  681                         sg++;
  682 
  683                         /* Sum the rest */
  684                         for (; num_sg != 0; num_sg--, sg++)
  685                                 ccb->csio.resid += sg->len;
  686                 }
  687                 /* Underruns are not errors */
  688                 ccb->ccb_h.status = CAM_REQ_CMP;
  689         }
  690 }
  691 
  692 static void
  693 ahbprocesserror(struct ahb_softc *ahb, struct ecb *ecb, union ccb *ccb)
  694 {
  695         struct hardware_ecb *hecb;
  696         struct ecb_status *status;
  697 
  698         hecb = &ecb->hecb;
  699         status = &ecb->status;
  700         switch (status->ha_status) {
  701         case HS_OK:
  702                 ccb->csio.scsi_status = status->scsi_status;
  703                 if (status->scsi_status != 0) {
  704                         ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
  705                         if (status->sense_stored) {
  706                                 ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
  707                                 ccb->csio.sense_resid =
  708                                     ccb->csio.sense_len - status->sense_len;
  709                                 bcopy(&ecb->sense, &ccb->csio.sense_data,
  710                                       status->sense_len);
  711                         }
  712                 }
  713                 break;
  714         case HS_TARGET_NOT_ASSIGNED:
  715                 ccb->ccb_h.status = CAM_PATH_INVALID;
  716                 break;
  717         case HS_SEL_TIMEOUT:
  718                 ccb->ccb_h.status = CAM_SEL_TIMEOUT;
  719                 break;
  720         case HS_DATA_RUN_ERR:
  721                 ahbcalcresid(ahb, ecb, ccb);
  722                 break;
  723         case HS_UNEXPECTED_BUSFREE:
  724                 ccb->ccb_h.status = CAM_UNEXP_BUSFREE;
  725                 break;
  726         case HS_INVALID_PHASE:
  727                 ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
  728                 break;
  729         case HS_REQUEST_SENSE_FAILED:
  730                 ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
  731                 break;
  732         case HS_TAG_MSG_REJECTED:
  733         {
  734                 struct ccb_trans_settings neg; 
  735 
  736                 xpt_print_path(ccb->ccb_h.path);
  737                 printf("refuses tagged commands.  Performing "
  738                        "non-tagged I/O\n");
  739                 neg.flags = 0;
  740                 neg.valid = CCB_TRANS_TQ_VALID;
  741                 xpt_setup_ccb(&neg.ccb_h, ccb->ccb_h.path, /*priority*/1); 
  742                 xpt_async(AC_TRANSFER_NEG, ccb->ccb_h.path, &neg);
  743                 ahb->tags_permitted &= ~(0x01 << ccb->ccb_h.target_id);
  744                 ccb->ccb_h.status = CAM_MSG_REJECT_REC;
  745                 break;
  746         }
  747         case HS_FIRMWARE_LOAD_REQ:
  748         case HS_HARDWARE_ERR:
  749                 /*
  750                  * Tell the system that the Adapter
  751                  * is no longer functional.
  752                  */
  753                 ccb->ccb_h.status = CAM_NO_HBA;
  754                 break;
  755         case HS_CMD_ABORTED_HOST:
  756         case HS_CMD_ABORTED_ADAPTER:
  757         case HS_ATN_TARGET_FAILED:
  758         case HS_SCSI_RESET_ADAPTER:
  759         case HS_SCSI_RESET_INCOMING:
  760                 ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
  761                 break;
  762         case HS_DUP_TCB_RECEIVED:
  763         case HS_INVALID_OPCODE:
  764         case HS_INVALID_CMD_LINK:
  765         case HS_INVALID_ECB_PARAM:
  766         case HS_PROGRAM_CKSUM_ERROR:
  767                 panic("ahb%ld: Can't happen host status %x occurred",
  768                       ahb->unit, status->ha_status);
  769                 break;
  770         }
  771         if (ccb->ccb_h.status != CAM_REQ_CMP) {
  772                 xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
  773                 ccb->ccb_h.status |= CAM_DEV_QFRZN;
  774         }
  775 }
  776 
  777 static void
  778 ahbdone(struct ahb_softc *ahb, u_int32_t mbox, u_int intstat)
  779 {
  780         struct ecb *ecb;
  781         union ccb *ccb;
  782 
  783         ecb = ahbecbptov(ahb, mbox);
  784 
  785         if ((ecb->state & ECB_ACTIVE) == 0)
  786                 panic("ecb not active");
  787 
  788         ccb = ecb->ccb;
  789 
  790         if (ccb != NULL) {
  791                 untimeout(ahbtimeout, ecb, ccb->ccb_h.timeout_ch);
  792                 LIST_REMOVE(&ccb->ccb_h, sim_links.le);
  793 
  794                 if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
  795                         bus_dmasync_op_t op;
  796 
  797                         if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
  798                                 op = BUS_DMASYNC_POSTREAD;
  799                         else
  800                                 op = BUS_DMASYNC_POSTWRITE;
  801                         bus_dmamap_sync(ahb->buffer_dmat, ecb->dmamap, op);
  802                         bus_dmamap_unload(ahb->buffer_dmat, ecb->dmamap);
  803                 }
  804 
  805                 if ((intstat & INTSTAT_MASK) == INTSTAT_ECB_OK) {
  806                         ccb->ccb_h.status = CAM_REQ_CMP;
  807                         ccb->csio.resid = 0;
  808                 } else {
  809                         ahbprocesserror(ahb, ecb, ccb);
  810                 }
  811                 ahbecbfree(ahb, ecb);
  812                 xpt_done(ccb);
  813         } else {
  814                 /* Non CCB Command */
  815                 if ((intstat & INTSTAT_MASK) != INTSTAT_ECB_OK) {
  816                         printf("ahb%ld: Command 0%x Failed %x:%x:%x\n",
  817                                ahb->unit, ecb->hecb.opcode,
  818                                *((u_int16_t*)&ecb->status),
  819                                ecb->status.ha_status, ecb->status.resid_count);
  820                 }
  821                 /* Client owns this ECB and will release it. */
  822         }
  823 }
  824 
  825 /*
  826  * Catch an interrupt from the adaptor
  827  */
  828 static void
  829 ahbintr(void *arg)
  830 {
  831         struct    ahb_softc *ahb;
  832         u_int     intstat;
  833         u_int32_t mbox;
  834 
  835         ahb = (struct ahb_softc *)arg;
  836 
  837         while (ahb_inb(ahb, HOSTSTAT) & HOSTSTAT_INTPEND) {
  838                 /*
  839                  * Fetch information about this interrupt.
  840                  */
  841                 intstat = ahb_inb(ahb, INTSTAT);
  842                 mbox = ahb_inl(ahb, MBOXIN0);
  843 
  844                 /*
  845                  * Reset interrupt latch.
  846                  */
  847                 ahb_outb(ahb, CONTROL, CNTRL_CLRINT);
  848 
  849                 /*
  850                  * Process the completed operation
  851                  */
  852                 switch (intstat & INTSTAT_MASK) {
  853                 case INTSTAT_ECB_OK:
  854                 case INTSTAT_ECB_CMPWRETRY:
  855                 case INTSTAT_ECB_CMPWERR:
  856                         ahbdone(ahb, mbox, intstat);
  857                         break;
  858                 case INTSTAT_AEN_OCCURED:
  859                         if ((intstat & INTSTAT_TARGET_MASK) == ahb->scsi_id) {
  860                                 /* Bus Reset */
  861                                 xpt_print_path(ahb->path);
  862                                 switch (mbox) {
  863                                 case HS_SCSI_RESET_ADAPTER:
  864                                         printf("Host Adapter Initiated "
  865                                                "Bus Reset occurred\n");
  866                                         break;
  867                                 case HS_SCSI_RESET_INCOMING:
  868                                         printf("Bus Reset Initiated "
  869                                                "by another device occurred\n");
  870                                         break;
  871                                 }
  872                                 /* Notify the XPT */
  873                                 xpt_async(AC_BUS_RESET, ahb->path, NULL);
  874                                 break;
  875                         }
  876                         printf("Unsupported initiator selection AEN occured\n");
  877                         break;
  878                 case INTSTAT_IMMED_OK:
  879                 case INTSTAT_IMMED_ERR:
  880                         ahbhandleimmed(ahb, mbox, intstat);
  881                         break;
  882                 case INTSTAT_HW_ERR:
  883                         panic("Unrecoverable hardware Error Occurred\n");
  884                 }
  885         }
  886 }
  887 
  888 static void
  889 ahbexecuteecb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
  890 {
  891         struct    ecb *ecb;
  892         union     ccb *ccb;
  893         struct    ahb_softc *ahb;
  894         u_int32_t ecb_paddr;
  895         int       s;
  896 
  897         ecb = (struct ecb *)arg;
  898         ccb = ecb->ccb;
  899         ahb = (struct ahb_softc *)ccb->ccb_h.ccb_ahb_ptr;
  900 
  901         if (error != 0) {
  902                 if (error != EFBIG)
  903                         printf("ahb%ld: Unexepected error 0x%x returned from "
  904                                "bus_dmamap_load\n", ahb->unit, error);
  905                 if (ccb->ccb_h.status == CAM_REQ_INPROG) {
  906                         xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
  907                         ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN;
  908                 }
  909                 ahbecbfree(ahb, ecb);
  910                 xpt_done(ccb);
  911                 return;
  912         }
  913                 
  914         ecb_paddr = ahbecbvtop(ahb, ecb);
  915 
  916         if (nseg != 0) {
  917                 ahb_sg_t *sg;
  918                 bus_dma_segment_t *end_seg;
  919                 bus_dmasync_op_t op;
  920 
  921                 end_seg = dm_segs + nseg;
  922 
  923                 /* Copy the segments into our SG list */
  924                 sg = ecb->sg_list;
  925                 while (dm_segs < end_seg) {
  926                         sg->addr = dm_segs->ds_addr;
  927                         sg->len = dm_segs->ds_len;
  928                         sg++;
  929                         dm_segs++;
  930                 }
  931 
  932                 if (nseg > 1) {
  933                         ecb->hecb.flag_word1 |= FW1_SG_ECB;
  934                         ecb->hecb.data_ptr = ahbsgpaddr(ecb_paddr);
  935                         ecb->hecb.data_len = sizeof(ahb_sg_t) * nseg;
  936                 } else {
  937                         ecb->hecb.data_ptr = ecb->sg_list->addr;
  938                         ecb->hecb.data_len = ecb->sg_list->len;
  939                 }
  940 
  941                 if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
  942 /*                      ecb->hecb.flag_word2 |= FW2_DATA_DIR_IN; */
  943                         op = BUS_DMASYNC_PREREAD;
  944                 } else {
  945                         op = BUS_DMASYNC_PREWRITE;
  946                 }
  947                 /* ecb->hecb.flag_word2 |= FW2_CHECK_DATA_DIR; */
  948 
  949                 bus_dmamap_sync(ahb->buffer_dmat, ecb->dmamap, op);
  950 
  951         } else {
  952                 ecb->hecb.data_ptr = 0;
  953                 ecb->hecb.data_len = 0;
  954         }
  955 
  956         s = splcam();
  957 
  958         /*
  959          * Last time we need to check if this CCB needs to
  960          * be aborted.
  961          */
  962         if (ccb->ccb_h.status != CAM_REQ_INPROG) {
  963                 if (nseg != 0)
  964                         bus_dmamap_unload(ahb->buffer_dmat, ecb->dmamap);
  965                 ahbecbfree(ahb, ecb);
  966                 xpt_done(ccb);
  967                 splx(s);
  968                 return;
  969         }
  970                 
  971         ecb->state = ECB_ACTIVE;
  972         ccb->ccb_h.status |= CAM_SIM_QUEUED;
  973         LIST_INSERT_HEAD(&ahb->pending_ccbs, &ccb->ccb_h, sim_links.le);
  974 
  975         /* Tell the adapter about this command */
  976         ahbqueuembox(ahb, ecb_paddr, ATTN_STARTECB|ccb->ccb_h.target_id);
  977 
  978         ccb->ccb_h.timeout_ch = timeout(ahbtimeout, (caddr_t)ecb,
  979                                         (ccb->ccb_h.timeout * hz) / 1000);
  980         splx(s);
  981 }
  982 
  983 static void
  984 ahbaction(struct cam_sim *sim, union ccb *ccb)
  985 {
  986         struct  ahb_softc *ahb;
  987 
  988         CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahbaction\n"));
  989         
  990         ahb = (struct ahb_softc *)cam_sim_softc(sim);
  991         
  992         switch (ccb->ccb_h.func_code) {
  993         /* Common cases first */
  994         case XPT_SCSI_IO:       /* Execute the requested I/O operation */
  995         {
  996                 struct ecb *ecb;
  997                 struct hardware_ecb *hecb;
  998 
  999                 /*
 1000                  * get an ecb to use.
 1001                  */
 1002                 if ((ecb = ahbecbget(ahb)) == NULL) {
 1003                         /* Should never occur */
 1004                         panic("Failed to get an ecb");
 1005                 }
 1006 
 1007                 /*
 1008                  * So we can find the ECB when an abort is requested
 1009                  */
 1010                 ecb->ccb = ccb;
 1011                 ccb->ccb_h.ccb_ecb_ptr = ecb;
 1012                 ccb->ccb_h.ccb_ahb_ptr = ahb;
 1013 
 1014                 /*
 1015                  * Put all the arguments for the xfer in the ecb
 1016                  */
 1017                 hecb = &ecb->hecb;
 1018                 hecb->opcode = ECBOP_INITIATOR_SCSI_CMD;
 1019                 hecb->flag_word1 = FW1_AUTO_REQUEST_SENSE
 1020                                  | FW1_ERR_STATUS_BLK_ONLY;
 1021                 hecb->flag_word2 = ccb->ccb_h.target_lun
 1022                                  | FW2_NO_RETRY_ON_BUSY;
 1023                 if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0) {
 1024                         hecb->flag_word2 |= FW2_TAG_ENB
 1025                                          | ((ccb->csio.tag_action & 0x3)
 1026                                             << FW2_TAG_TYPE_SHIFT);
 1027                 }
 1028                 if ((ccb->ccb_h.flags & CAM_DIS_DISCONNECT) != 0)
 1029                         hecb->flag_word2 |= FW2_DISABLE_DISC;
 1030                 hecb->sense_len = ccb->csio.sense_len;
 1031                 hecb->cdb_len = ccb->csio.cdb_len;
 1032                 if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
 1033                         if ((ccb->ccb_h.flags & CAM_CDB_PHYS) == 0) {
 1034                                 bcopy(ccb->csio.cdb_io.cdb_ptr,
 1035                                       hecb->cdb, hecb->cdb_len);
 1036                         } else {
 1037                                 /* I guess I could map it in... */
 1038                                 ccb->ccb_h.status = CAM_REQ_INVALID;
 1039                                 ahbecbfree(ahb, ecb);
 1040                                 xpt_done(ccb);
 1041                                 return;
 1042                         }
 1043                 } else {
 1044                         bcopy(ccb->csio.cdb_io.cdb_bytes,
 1045                               hecb->cdb, hecb->cdb_len);
 1046                 }
 1047 
 1048                 /*
 1049                  * If we have any data to send with this command,
 1050                  * map it into bus space.
 1051                  */
 1052                 if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
 1053                         if ((ccb->ccb_h.flags & CAM_SCATTER_VALID) == 0) {
 1054                                 /*
 1055                                  * We've been given a pointer
 1056                                  * to a single buffer.
 1057                                  */
 1058                                 if ((ccb->ccb_h.flags & CAM_DATA_PHYS)==0) {
 1059                                         int s;
 1060                                         int error;
 1061 
 1062                                         s = splsoftvm();
 1063                                         error = bus_dmamap_load(
 1064                                             ahb->buffer_dmat,
 1065                                             ecb->dmamap,
 1066                                             ccb->csio.data_ptr,
 1067                                             ccb->csio.dxfer_len,
 1068                                             ahbexecuteecb,
 1069                                             ecb, /*flags*/0);
 1070                                         if (error == EINPROGRESS) {
 1071                                                 /*
 1072                                                  * So as to maintain ordering,
 1073                                                  * freeze the controller queue
 1074                                                  * until our mapping is
 1075                                                  * returned.
 1076                                                  */
 1077                                                 xpt_freeze_simq(ahb->sim, 1);
 1078                                                 ccb->ccb_h.status |=
 1079                                                     CAM_RELEASE_SIMQ;
 1080                                         }
 1081                                         splx(s);
 1082                                 } else {
 1083                                         struct bus_dma_segment seg; 
 1084 
 1085                                         /* Pointer to physical buffer */
 1086                                         seg.ds_addr =
 1087                                             (bus_addr_t)ccb->csio.data_ptr;
 1088                                         seg.ds_len = ccb->csio.dxfer_len;
 1089                                         ahbexecuteecb(ecb, &seg, 1, 0);
 1090                                 }
 1091                         } else {
 1092                                 struct bus_dma_segment *segs;
 1093 
 1094                                 if ((ccb->ccb_h.flags & CAM_DATA_PHYS) != 0)
 1095                                         panic("ahbaction - Physical segment "
 1096                                               "pointers unsupported");
 1097 
 1098                                 if ((ccb->ccb_h.flags & CAM_SG_LIST_PHYS) == 0)
 1099                                         panic("btaction - Virtual segment "
 1100                                               "addresses unsupported");
 1101 
 1102                                 /* Just use the segments provided */
 1103                                 segs = (struct bus_dma_segment *)
 1104                                     ccb->csio.data_ptr;
 1105                                 ahbexecuteecb(ecb, segs, ccb->csio.sglist_cnt,
 1106                                              0);
 1107                         }
 1108                 } else {
 1109                         ahbexecuteecb(ecb, NULL, 0, 0);
 1110                 }
 1111                 break;
 1112         }
 1113         case XPT_EN_LUN:                /* Enable LUN as a target */
 1114         case XPT_TARGET_IO:             /* Execute target I/O request */
 1115         case XPT_ACCEPT_TARGET_IO:      /* Accept Host Target Mode CDB */
 1116         case XPT_CONT_TARGET_IO:        /* Continue Host Target I/O Connection*/
 1117         case XPT_ABORT:                 /* Abort the specified CCB */
 1118                 /* XXX Implement */
 1119                 ccb->ccb_h.status = CAM_REQ_INVALID;
 1120                 xpt_done(ccb);
 1121                 break;
 1122         case XPT_SET_TRAN_SETTINGS:
 1123         {
 1124                 ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
 1125                 xpt_done(ccb);
 1126                 break;
 1127         }
 1128         case XPT_GET_TRAN_SETTINGS:
 1129         /* Get default/user set transfer settings for the target */
 1130         {
 1131                 struct  ccb_trans_settings *cts;
 1132                 u_int   target_mask;
 1133 
 1134                 cts = &ccb->cts;
 1135                 target_mask = 0x01 << ccb->ccb_h.target_id;
 1136                 if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) {
 1137                         cts->flags = 0;
 1138                         if ((ahb->disc_permitted & target_mask) != 0)
 1139                                 cts->flags |= CCB_TRANS_DISC_ENB;
 1140                         if ((ahb->tags_permitted & target_mask) != 0)
 1141                                 cts->flags |= CCB_TRANS_TAG_ENB;
 1142                         cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
 1143                         cts->sync_period = 25; /* 10MHz */
 1144 
 1145                         if (cts->sync_period != 0)
 1146                                 cts->sync_offset = 15;
 1147 
 1148                         cts->valid = CCB_TRANS_SYNC_RATE_VALID
 1149                                    | CCB_TRANS_SYNC_OFFSET_VALID
 1150                                    | CCB_TRANS_BUS_WIDTH_VALID
 1151                                    | CCB_TRANS_DISC_VALID
 1152                                    | CCB_TRANS_TQ_VALID;
 1153                         ccb->ccb_h.status = CAM_REQ_CMP;
 1154                 } else {
 1155                         ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
 1156                 }
 1157                 xpt_done(ccb);
 1158                 break;
 1159         }
 1160         case XPT_RESET_DEV:     /* Bus Device Reset the specified SCSI device */
 1161         {
 1162                 int i;
 1163                 int s;
 1164 
 1165                 s = splcam();
 1166                 ahb->immed_cmd = IMMED_RESET;
 1167                 ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ccb->ccb_h.target_id);
 1168                 /* Poll for interrupt completion */
 1169                 for (i = 1000; ahb->immed_cmd != 0 && i != 0; i--) {
 1170                         DELAY(1000);
 1171                         ahbintr(cam_sim_softc(sim));
 1172                 }
 1173                 splx(s);
 1174                 break;
 1175         }
 1176         case XPT_CALC_GEOMETRY:
 1177         {
 1178                 struct    ccb_calc_geometry *ccg;
 1179                 u_int32_t size_mb;
 1180                 u_int32_t secs_per_cylinder;
 1181 
 1182                 ccg = &ccb->ccg;
 1183                 size_mb = ccg->volume_size
 1184                         / ((1024L * 1024L) / ccg->block_size);
 1185                 
 1186                 if (size_mb > 1024 && (ahb->extended_trans != 0)) {
 1187                         ccg->heads = 255;
 1188                         ccg->secs_per_track = 63;
 1189                 } else {
 1190                         ccg->heads = 64;
 1191                         ccg->secs_per_track = 32;
 1192                 }
 1193                 secs_per_cylinder = ccg->heads * ccg->secs_per_track;
 1194                 ccg->cylinders = ccg->volume_size / secs_per_cylinder;
 1195                 ccb->ccb_h.status = CAM_REQ_CMP;
 1196                 xpt_done(ccb);
 1197                 break;
 1198         }
 1199         case XPT_RESET_BUS:             /* Reset the specified SCSI bus */
 1200         {
 1201                 int i;
 1202 
 1203                 ahb->immed_cmd = IMMED_RESET;
 1204                 ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ahb->scsi_id);
 1205                 /* Poll for interrupt completion */
 1206                 for (i = 1000; ahb->immed_cmd != 0 && i != 0; i--)
 1207                         DELAY(1000);
 1208                 ccb->ccb_h.status = CAM_REQ_CMP;
 1209                 xpt_done(ccb);
 1210                 break;
 1211         }
 1212         case XPT_TERM_IO:               /* Terminate the I/O process */
 1213                 /* XXX Implement */
 1214                 ccb->ccb_h.status = CAM_REQ_INVALID;
 1215                 xpt_done(ccb);
 1216                 break;
 1217         case XPT_PATH_INQ:              /* Path routing inquiry */
 1218         {
 1219                 struct ccb_pathinq *cpi = &ccb->cpi;
 1220                 
 1221                 cpi->version_num = 1; /* XXX??? */
 1222                 cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE;
 1223                 cpi->target_sprt = 0;
 1224                 cpi->hba_misc = 0;
 1225                 cpi->hba_eng_cnt = 0;
 1226                 cpi->max_target = 7;
 1227                 cpi->max_lun = 7;
 1228                 cpi->initiator_id = ahb->scsi_id;
 1229                 cpi->bus_id = cam_sim_bus(sim);
 1230                 cpi->base_transfer_speed = 3300;
 1231                 strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
 1232                 strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN);
 1233                 strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
 1234                 cpi->unit_number = cam_sim_unit(sim);
 1235                 cpi->ccb_h.status = CAM_REQ_CMP;
 1236                 xpt_done(ccb);
 1237                 break;
 1238         }
 1239 #if 0
 1240         /* Need these??? */
 1241         case XPT_IMMED_NOTIFY:          /* Notify Host Target driver of event */
 1242         case XPT_NOTIFY_ACK:            /* Acknowledgement of event */
 1243 #endif
 1244         default:
 1245                 ccb->ccb_h.status = CAM_REQ_INVALID;
 1246                 xpt_done(ccb);
 1247                 break;
 1248         }
 1249 }
 1250 
 1251 static void
 1252 ahbpoll(struct cam_sim *sim)
 1253 {
 1254         ahbintr(cam_sim_softc(sim));
 1255 }
 1256 
 1257 void
 1258 ahbtimeout(void *arg)
 1259 {
 1260         struct ecb       *ecb;
 1261         union  ccb       *ccb;
 1262         struct ahb_softc *ahb;
 1263         int               s;
 1264 
 1265         ecb = (struct ecb *)arg;
 1266         ccb = ecb->ccb;
 1267         ahb = (struct ahb_softc *)ccb->ccb_h.ccb_ahb_ptr;
 1268         xpt_print_path(ccb->ccb_h.path);
 1269         printf("ECB %p - timed out\n", (void *)ecb);
 1270 
 1271         s = splcam();
 1272 
 1273         if ((ecb->state & ECB_ACTIVE) == 0) {
 1274                 xpt_print_path(ccb->ccb_h.path);
 1275                 printf("ECB %p - timed out ECB already completed\n",
 1276                        (void *)ecb);
 1277                 splx(s);
 1278                 return;
 1279         }
 1280         /*
 1281          * In order to simplify the recovery process, we ask the XPT
 1282          * layer to halt the queue of new transactions and we traverse
 1283          * the list of pending CCBs and remove their timeouts. This
 1284          * means that the driver attempts to clear only one error
 1285          * condition at a time.  In general, timeouts that occur
 1286          * close together are related anyway, so there is no benefit
 1287          * in attempting to handle errors in parrallel.  Timeouts will
 1288          * be reinstated when the recovery process ends.
 1289          */
 1290         if ((ecb->state & ECB_DEVICE_RESET) == 0) {
 1291                 struct ccb_hdr *ccb_h;
 1292 
 1293                 if ((ecb->state & ECB_RELEASE_SIMQ) == 0) {
 1294                         xpt_freeze_simq(ahb->sim, /*count*/1);
 1295                         ecb->state |= ECB_RELEASE_SIMQ;
 1296                 }
 1297 
 1298                 ccb_h = LIST_FIRST(&ahb->pending_ccbs);
 1299                 while (ccb_h != NULL) {
 1300                         struct ecb *pending_ecb;
 1301 
 1302                         pending_ecb = (struct ecb *)ccb_h->ccb_ecb_ptr;
 1303                         untimeout(ahbtimeout, pending_ecb, ccb_h->timeout_ch);
 1304                         ccb_h = LIST_NEXT(ccb_h, sim_links.le);
 1305                 }
 1306 
 1307                 /* Store for our interrupt handler */
 1308                 ahb->immed_ecb = ecb;
 1309 
 1310                 /*    
 1311                  * Send a Bus Device Reset message:
 1312                  * The target that is holding up the bus may not
 1313                  * be the same as the one that triggered this timeout
 1314                  * (different commands have different timeout lengths),
 1315                  * but we have no way of determining this from our
 1316                  * timeout handler.  Our strategy here is to queue a
 1317                  * BDR message to the target of the timed out command.
 1318                  * If this fails, we'll get another timeout 2 seconds
 1319                  * later which will attempt a bus reset.
 1320                  */
 1321                 xpt_print_path(ccb->ccb_h.path);
 1322                 printf("Queuing BDR\n");
 1323                 ecb->state |= ECB_DEVICE_RESET;
 1324                 ccb->ccb_h.timeout_ch =
 1325                     timeout(ahbtimeout, (caddr_t)ecb, 2 * hz);
 1326 
 1327                 ahb->immed_cmd = IMMED_RESET;
 1328                 ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ccb->ccb_h.target_id);
 1329         } else if ((ecb->state & ECB_SCSIBUS_RESET) != 0) {
 1330                 /*
 1331                  * Try a SCSI bus reset.  We do this only if we
 1332                  * have already attempted to clear the condition with a BDR.
 1333                  */
 1334                 xpt_print_path(ccb->ccb_h.path);
 1335                 printf("Attempting SCSI Bus reset\n");
 1336                 ecb->state |= ECB_SCSIBUS_RESET;
 1337                 ccb->ccb_h.timeout_ch =
 1338                     timeout(ahbtimeout, (caddr_t)ecb, 2 * hz);
 1339                 ahb->immed_cmd = IMMED_RESET;
 1340                 ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ahb->scsi_id);
 1341         } else {
 1342                 /* Bring out the hammer... */
 1343                 ahbreset(ahb);
 1344 
 1345                 /* Simulate the reset complete interrupt */
 1346                 ahbhandleimmed(ahb, 0, ahb->scsi_id|INTSTAT_IMMED_OK);
 1347         }
 1348 
 1349         splx(s);
 1350 }
 1351 
 1352 #endif /* NEISA */

Cache object: 61fe206eaa139ae86e76184ac0ae3a50


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