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/mca/edc_mca.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 /*      $NetBSD: edc_mca.c,v 1.23 2003/11/10 08:51:52 wiz Exp $ */
    2 
    3 /*
    4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
    5  *
    6  * This code is derived from software contributed to The NetBSD Foundation
    7  * by Jaromir Dolecek.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 3. All advertising materials mentioning features or use of this software
   18  *    must display the following acknowledgement:
   19  *        This product includes software developed by the NetBSD
   20  *        Foundation, Inc. and its contributors.
   21  * 4. The name of the author may not be used to endorse or promote products
   22  *    derived from this software without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   26  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   27  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   29  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   30  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   31  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   32  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   33  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   34  */
   35 
   36 /*
   37  * Driver for MCA ESDI controllers and disks conforming to IBM DASD
   38  * spec.
   39  *
   40  * The driver was written with DASD Storage Interface Specification
   41  * for MCA rev. 2.2 in hands, thanks to Scott Telford <st@epcc.ed.ac.uk>.
   42  *
   43  * TODO:
   44  * - improve error recovery
   45  *   Issue soft reset on error or timeout?
   46  * - test with > 1 disk (this is supported by some controllers)
   47  * - test with > 1 ESDI controller in machine; shared interrupts
   48  *   necessary for this to work should be supported - edc_intr() specifically
   49  *   checks if the interrupt is for this controller
   50  */
   51 
   52 #include <sys/cdefs.h>
   53 __KERNEL_RCSID(0, "$NetBSD: edc_mca.c,v 1.23 2003/11/10 08:51:52 wiz Exp $");
   54 
   55 #include "rnd.h"
   56 
   57 #include <sys/param.h>
   58 #include <sys/systm.h>
   59 #include <sys/errno.h>
   60 #include <sys/device.h>
   61 #include <sys/malloc.h>
   62 #include <sys/endian.h>
   63 #include <sys/disklabel.h>
   64 #include <sys/disk.h>
   65 #include <sys/syslog.h>
   66 #include <sys/proc.h>
   67 #include <sys/vnode.h>
   68 #include <sys/kernel.h>
   69 #include <sys/kthread.h>
   70 #if NRND > 0
   71 #include <sys/rnd.h>
   72 #endif
   73 
   74 #include <machine/bus.h>
   75 #include <machine/intr.h>
   76 
   77 #include <dev/mca/mcareg.h>
   78 #include <dev/mca/mcavar.h>
   79 #include <dev/mca/mcadevs.h>
   80 
   81 #include <dev/mca/edcreg.h>
   82 #include <dev/mca/edvar.h>
   83 #include <dev/mca/edcvar.h>
   84 
   85 #define EDC_ATTN_MAXTRIES       10000   /* How many times check for unbusy */
   86 #define EDC_MAX_CMD_RES_LEN     8
   87 
   88 struct edc_mca_softc {
   89         struct device sc_dev;
   90 
   91         bus_space_tag_t sc_iot;
   92         bus_space_handle_t sc_ioh;
   93 
   94         /* DMA related stuff */
   95         bus_dma_tag_t sc_dmat;          /* DMA tag as passed by parent */
   96         bus_dmamap_t  sc_dmamap_xfer;   /* transfer dma map */
   97 
   98         void    *sc_ih;                         /* interrupt handle */
   99 
  100         int     sc_flags;
  101 #define DASD_QUIET      0x01            /* don't dump cmd error info */
  102 
  103 #define DASD_MAXDEVS    8
  104         struct ed_softc *sc_ed[DASD_MAXDEVS];
  105         int sc_maxdevs;                 /* max number of disks attached to this
  106                                          * controller */
  107 
  108         /* I/O results variables */
  109         volatile int sc_stat;
  110 #define STAT_START      0
  111 #define STAT_ERROR      1
  112 #define STAT_DONE       2
  113         volatile int sc_resblk;         /* residual block count */
  114 
  115         /* CMD status block - only set & used in edc_intr() */
  116         u_int16_t status_block[EDC_MAX_CMD_RES_LEN];
  117 };
  118 
  119 int     edc_mca_probe   __P((struct device *, struct cfdata *, void *));
  120 void    edc_mca_attach  __P((struct device *, struct device *, void *));
  121 
  122 CFATTACH_DECL(edc_mca, sizeof(struct edc_mca_softc),
  123     edc_mca_probe, edc_mca_attach, NULL, NULL);
  124 
  125 static int      edc_intr __P((void *));
  126 static void     edc_dump_status_block __P((struct edc_mca_softc *,
  127                     u_int16_t *, int));
  128 static int      edc_do_attn __P((struct edc_mca_softc *, int, int, int));
  129 static void     edc_cmd_wait __P((struct edc_mca_softc *, int, int));
  130 static void     edcworker __P((void *));
  131 static void     edc_spawn_worker __P((void *));
  132 
  133 int
  134 edc_mca_probe(parent, match, aux)
  135         struct device *parent;
  136         struct cfdata *match;
  137         void *aux;
  138 {
  139         struct mca_attach_args *ma = aux;
  140 
  141         switch (ma->ma_id) {
  142         case MCA_PRODUCT_IBM_ESDIC:
  143         case MCA_PRODUCT_IBM_ESDIC_IG:
  144                 return (1);
  145         default:
  146                 return (0);
  147         }
  148 }
  149 
  150 void
  151 edc_mca_attach(parent, self, aux)
  152         struct device *parent, *self;
  153         void *aux;
  154 {
  155         struct edc_mca_softc *sc = (void *) self;
  156         struct mca_attach_args *ma = aux;
  157         struct ed_attach_args eda;
  158         int pos2, pos3, pos4;
  159         int irq, drq, iobase;
  160         const char *typestr;
  161         int devno, error;
  162 
  163         pos2 = mca_conf_read(ma->ma_mc, ma->ma_slot, 2);
  164         pos3 = mca_conf_read(ma->ma_mc, ma->ma_slot, 3);
  165         pos4 = mca_conf_read(ma->ma_mc, ma->ma_slot, 4);
  166 
  167         /*
  168          * POS register 2: (adf pos0)
  169          * 
  170          * 7 6 5 4 3 2 1 0
  171          *   \ \____/  \ \__ enable: 0=adapter disabled, 1=adapter enabled
  172          *    \     \   \___ Primary/Alternate Port Addresses:
  173          *     \     \          0=0x3510-3517 1=0x3518-0x351f
  174          *      \     \_____ DMA Arbitration Level: 0101=5 0110=6 0111=7
  175          *       \              0000=0 0001=1 0011=3 0100=4
  176          *        \_________ Fairness On/Off: 1=On 0=Off
  177          *
  178          * POS register 3: (adf pos1)
  179          * 
  180          * 7 6 5 4 3 2 1 0
  181          * 0 0 \_/
  182          *       \__________ DMA Burst Pacing Interval: 10=24ms 11=31ms
  183          *                     01=16ms 00=Burst Disabled
  184          *
  185          * POS register 4: (adf pos2)
  186          * 
  187          * 7 6 5 4 3 2 1 0
  188          *           \_/ \__ DMA Pacing Control: 1=Disabled 0=Enabled
  189          *             \____ Time to Release: 1X=6ms 01=3ms 00=Immediate
  190          *
  191          * IRQ is fixed to 14 (0x0e).
  192          */
  193 
  194         switch (ma->ma_id) {
  195         case MCA_PRODUCT_IBM_ESDIC:
  196                 typestr = "IBM ESDI Fixed Disk Controller";
  197                 break;
  198         case MCA_PRODUCT_IBM_ESDIC_IG:
  199                 typestr = "IBM Integ. ESDI Fixed Disk & Controller";
  200                 break;
  201         default:
  202                 typestr = NULL;
  203                 break;
  204         }
  205                 
  206         irq = ESDIC_IRQ;
  207         iobase = (pos2 & IO_IS_ALT) ? ESDIC_IOALT : ESDIC_IOPRM;
  208         drq = (pos2 & DRQ_MASK) >> 2;
  209 
  210         printf(" slot %d irq %d drq %d: %s\n", ma->ma_slot+1,
  211                 irq, drq, typestr);
  212 
  213 #ifdef DIAGNOSTIC
  214         /*
  215          * It's not strictly necessary to check this, machine configuration
  216          * utility uses only valid addresses.
  217          */
  218         if (drq == 2 || drq >= 8) {
  219                 printf("%s: invalid DMA Arbitration Level %d\n",
  220                         sc->sc_dev.dv_xname, drq);
  221                 return;
  222         }
  223 #endif
  224 
  225         printf("%s: Fairness %s, Release %s, ",
  226                 sc->sc_dev.dv_xname,
  227                 (pos2 & FAIRNESS_ENABLE) ? "On" : "Off",
  228                 (pos4 & RELEASE_1) ? "6ms"
  229                                 : ((pos4 & RELEASE_2) ? "3ms" : "Immediate")
  230                 );
  231         if ((pos4 & PACING_CTRL_DISABLE) == 0) {
  232                 static const char * const pacint[] =
  233                         { "disabled", "16ms", "24ms", "31ms"};
  234                 printf("DMA burst pacing interval %s\n",
  235                         pacint[(pos3 & PACING_INT_MASK) >> 4]);
  236         } else
  237                 printf("DMA pacing control disabled\n");
  238 
  239         sc->sc_iot = ma->ma_iot;
  240 
  241         if (bus_space_map(sc->sc_iot, iobase,
  242             ESDIC_REG_NPORTS, 0, &sc->sc_ioh)) {
  243                 printf("%s: couldn't map registers\n",
  244                     sc->sc_dev.dv_xname);
  245                 return;
  246         }
  247 
  248         sc->sc_ih = mca_intr_establish(ma->ma_mc, irq, IPL_BIO, edc_intr, sc);
  249         if (sc->sc_ih == NULL) {
  250                 printf("%s: couldn't establish interrupt handler\n",
  251                         sc->sc_dev.dv_xname);
  252                 return;
  253         }
  254 
  255         /* Create a MCA DMA map, used for data transfer */
  256         sc->sc_dmat = ma->ma_dmat;
  257         if ((error = mca_dmamap_create(sc->sc_dmat, MAXPHYS,
  258             BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW | MCABUS_DMA_16BIT,
  259             &sc->sc_dmamap_xfer, drq)) != 0){
  260                 printf("%s: couldn't create DMA map - error %d\n",
  261                         sc->sc_dev.dv_xname, error);
  262                 return;
  263         }
  264 
  265         /*
  266          * Integrated ESDI controller supports only one disk, other
  267          * controllers support two disks.
  268          */
  269         if (ma->ma_id == MCA_PRODUCT_IBM_ESDIC_IG)
  270                 sc->sc_maxdevs = 1;
  271         else
  272                 sc->sc_maxdevs = 2;
  273 
  274         /*
  275          * Reset controller and attach individual disks. ed attach routine
  276          * uses polling so that this works with interrupts disabled.
  277          */
  278 
  279         /* Do a reset to ensure sane state after warm boot. */
  280         if (bus_space_read_1(sc->sc_iot, sc->sc_ioh, BSR) & BSR_BUSY) {
  281                 /* hard reset */
  282                 printf("%s: controller busy, performing hardware reset ...\n",
  283                         sc->sc_dev.dv_xname);
  284                 bus_space_write_1(sc->sc_iot, sc->sc_ioh, BCR,
  285                         BCR_INT_ENABLE|BCR_RESET);
  286         } else {
  287                 /* "SOFT" reset */
  288                 edc_do_attn(sc, ATN_RESET_ATTACHMENT, DASD_DEVNO_CONTROLLER,0);
  289         }
  290                 
  291         /*
  292          * Since interrupts are disabled, it's necessary
  293          * to detect the interrupt request and call edc_intr()
  294          * explicitly. See also edc_run_cmd().
  295          */
  296         while(bus_space_read_1(sc->sc_iot, sc->sc_ioh, BSR) & BSR_BUSY) {
  297                 if (bus_space_read_1(sc->sc_iot, sc->sc_ioh, BSR) & BSR_INTR)
  298                         edc_intr(sc);
  299 
  300                 delay(100);
  301         }
  302 
  303         /* be quiet during probes */
  304         sc->sc_flags |= DASD_QUIET;
  305 
  306         /* check for attached disks */
  307         for(devno=0; devno < sc->sc_maxdevs; devno++) {
  308                 eda.edc_drive = devno;
  309                 sc->sc_ed[devno] =
  310                         (void *) config_found_sm(self, &eda, NULL, NULL);
  311 
  312                 /* If initialization did not succeed, NULL the pointer. */
  313                 if (sc->sc_ed[devno]
  314                     && (sc->sc_ed[devno]->sc_flags & EDF_INIT) == 0)
  315                         sc->sc_ed[devno] = NULL;
  316         }
  317 
  318         /* enable full error dumps again */
  319         sc->sc_flags &= ~DASD_QUIET;
  320 
  321         /*
  322          * Check if there are any disks attached. If not, disestablish
  323          * the interrupt.
  324          */
  325         for(devno=0; devno < sc->sc_maxdevs; devno++) {
  326                 if (sc->sc_ed[devno])
  327                         break;
  328         }
  329 
  330         if (devno == sc->sc_maxdevs) {
  331                 printf("%s: disabling controller (no drives attached)\n",
  332                         sc->sc_dev.dv_xname);
  333                 mca_intr_disestablish(ma->ma_mc, sc->sc_ih);
  334                 return;
  335         }
  336 
  337         /*
  338          * Run the worker thread.
  339          */
  340         config_pending_incr();
  341         kthread_create(edc_spawn_worker, (void *) sc);
  342 }
  343 
  344 void
  345 edc_add_disk(sc, ed)
  346         struct edc_mca_softc *sc;
  347         struct ed_softc *ed;
  348 {
  349         sc->sc_ed[ed->sc_devno] = ed;
  350 }
  351 
  352 static int
  353 edc_intr(arg)
  354         void *arg;
  355 {
  356         struct edc_mca_softc *sc = arg;
  357         u_int8_t isr, intr_id;
  358         u_int16_t sifr;
  359         int cmd=-1, devno;
  360 
  361         /*
  362          * Check if the interrupt was for us.
  363          */
  364         if ((bus_space_read_1(sc->sc_iot, sc->sc_ioh, BSR) & BSR_INTR) == 0)
  365                 return (0);
  366 
  367         /*
  368          * Read ISR to find out interrupt type. This also clears the interrupt
  369          * condition and BSR_INTR flag. Accordings to docs interrupt ID of 0, 2
  370          * and 4 are reserved and not used.
  371          */
  372         isr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ISR);
  373         intr_id = isr & ISR_INTR_ID_MASK;
  374 
  375 #ifdef EDC_DEBUG
  376         if (intr_id == 0 || intr_id == 2 || intr_id == 4) {
  377                 printf("%s: bogus interrupt id %d\n", sc->sc_dev.dv_xname,
  378                         (int) intr_id);
  379                 return (0);
  380         }
  381 #endif
  382 
  383         /* Get number of device whose intr this was */
  384         devno = (isr & 0xe0) >> 5;
  385 
  386         /*
  387          * Get Status block. Higher byte always says how long the status
  388          * block is, rest is device number and command code.
  389          * Check the status block length against our supported maximum length
  390          * and fetch the data.
  391          */
  392         if (bus_space_read_1(sc->sc_iot, sc->sc_ioh,BSR) & BSR_SIFR_FULL) {
  393                 size_t len;
  394                 int i;
  395 
  396                 sifr = le16toh(bus_space_read_2(sc->sc_iot, sc->sc_ioh, SIFR));
  397                 len = (sifr & 0xff00) >> 8;
  398 #ifdef DEBUG
  399                 if (len > EDC_MAX_CMD_RES_LEN)
  400                         panic("%s: maximum Status Length exceeded: %d > %d",
  401                                 sc->sc_dev.dv_xname,
  402                                 len, EDC_MAX_CMD_RES_LEN);
  403 #endif
  404 
  405                 /* Get command code */
  406                 cmd = sifr & SIFR_CMD_MASK;
  407 
  408                 /* Read whole status block */
  409                 sc->status_block[0] = sifr;
  410                 for(i=1; i < len; i++) {
  411                         while((bus_space_read_1(sc->sc_iot, sc->sc_ioh, BSR)
  412                                 & BSR_SIFR_FULL) == 0)
  413                                 ;
  414 
  415                         sc->status_block[i] = le16toh(
  416                                 bus_space_read_2(sc->sc_iot, sc->sc_ioh, SIFR));
  417                 }
  418                 /* zero out rest */
  419                 if (i < EDC_MAX_CMD_RES_LEN) {
  420                         memset(&sc->status_block[i], 0,
  421                                 (EDC_MAX_CMD_RES_LEN-i)*sizeof(u_int16_t));
  422                 }
  423         }
  424 
  425         switch (intr_id) {
  426         case ISR_DATA_TRANSFER_RDY:
  427                 /*
  428                  * Ready to do DMA. The DMA controller has already been
  429                  * setup, now just kick disk controller to do the transfer.
  430                  */
  431                 bus_space_write_1(sc->sc_iot, sc->sc_ioh, BCR,
  432                         BCR_INT_ENABLE|BCR_DMA_ENABLE);
  433                 break;
  434 
  435         case ISR_COMPLETED:
  436         case ISR_COMPLETED_WITH_ECC:
  437         case ISR_COMPLETED_RETRIES:
  438         case ISR_COMPLETED_WARNING:
  439                 /*
  440                  * Copy device config data if appropriate. sc->sc_ed[]
  441                  * entry might be NULL during probe.
  442                  */
  443                 if (cmd == CMD_GET_DEV_CONF && sc->sc_ed[devno]) {
  444                         memcpy(sc->sc_ed[devno]->sense_data, sc->status_block,
  445                                 sizeof(sc->sc_ed[devno]->sense_data));
  446                 }
  447 
  448                 sc->sc_stat = STAT_DONE;
  449                 break;
  450 
  451         case ISR_RESET_COMPLETED:
  452         case ISR_ABORT_COMPLETED:
  453                 /* nothing to do */
  454                 break;
  455 
  456         case ISR_ATTN_ERROR:
  457                 /*
  458                  * Basically, this means driver bug or something seriously
  459                  * hosed. panic rather than extending the lossage. 
  460                  * No status block available, so no further info.
  461                  */
  462                 panic("%s: dev %d: attention error",
  463                         sc->sc_dev.dv_xname,
  464                         devno);
  465                 /* NOTREACHED */
  466                 break;
  467 
  468         default:
  469                 if ((sc->sc_flags & DASD_QUIET) == 0)
  470                         edc_dump_status_block(sc, sc->status_block, intr_id);
  471 
  472                 sc->sc_stat = STAT_ERROR;
  473                 break;
  474         }
  475                         
  476         /*
  477          * Unless the interrupt is for Data Transfer Ready or
  478          * Attention Error, finish by assertion EOI. This makes
  479          * attachment aware the interrupt is processed and system
  480          * is ready to accept another one.
  481          */
  482         if (intr_id != ISR_DATA_TRANSFER_RDY && intr_id != ISR_ATTN_ERROR)
  483                 edc_do_attn(sc, ATN_END_INT, devno, intr_id);
  484 
  485         /* If Read or Write Data, wakeup worker thread to finish it */
  486         if (intr_id != ISR_DATA_TRANSFER_RDY) {
  487                 if (cmd == CMD_READ_DATA || cmd == CMD_WRITE_DATA)
  488                         sc->sc_resblk = sc->status_block[SB_RESBLKCNT_IDX];
  489                 wakeup_one(sc);
  490         }
  491 
  492         return (1);
  493 }
  494 
  495 /*
  496  * This follows the exact order for Attention Request as
  497  * written in DASD Storage Interface Specification MC (Rev 2.2).
  498  */ 
  499 static int
  500 edc_do_attn(sc, attn_type, devno, intr_id)
  501         struct edc_mca_softc *sc;
  502         int attn_type, devno, intr_id;
  503 {
  504         int tries;
  505 
  506         /* 1. Disable interrupts in BCR. */
  507         bus_space_write_1(sc->sc_iot, sc->sc_ioh, BCR, 0);
  508 
  509         /*
  510          * 2. Assure NOT BUSY and NO INTERRUPT PENDING, unless acknowledging
  511          *    a RESET COMPLETED interrupt.
  512          */
  513         if (intr_id != ISR_RESET_COMPLETED) {
  514 #ifdef EDC_DEBUG
  515                 if (attn_type == ATN_CMD_REQ
  516                     && (bus_space_read_1(sc->sc_iot, sc->sc_ioh, BSR)
  517                             & BSR_INT_PENDING))
  518                         panic("%s: edc int pending", sc->sc_dev.dv_xname);
  519 #endif
  520 
  521                 for(tries=1; tries < EDC_ATTN_MAXTRIES; tries++) {
  522                         if ((bus_space_read_1(sc->sc_iot, sc->sc_ioh, BSR)
  523                              & BSR_BUSY) == 0)
  524                                 break;
  525                 }
  526 
  527                 if (tries == EDC_ATTN_MAXTRIES) {
  528                         printf("%s: edc_do_attn: timeout waiting for attachment to become available\n",
  529                                         sc->sc_ed[devno]->sc_dev.dv_xname);
  530                         return (EIO);
  531                 }
  532         }
  533 
  534         /*
  535          * 3. Write proper DEVICE NUMBER and Attention number to ATN.
  536          */ 
  537         bus_space_write_1(sc->sc_iot, sc->sc_ioh, ATN, attn_type | (devno<<5));
  538 
  539         /*
  540          * 4. Enable interrupts via BCR.
  541          */
  542         bus_space_write_1(sc->sc_iot, sc->sc_ioh, BCR, BCR_INT_ENABLE);
  543 
  544         return (0);
  545 }
  546 
  547 /*
  548  * Wait until command is processed, timeout after 'secs' seconds.
  549  * We use mono_time, since we don't need actual RTC, just time
  550  * interval.
  551  */
  552 static void
  553 edc_cmd_wait(sc, secs, poll)
  554         struct edc_mca_softc *sc;
  555         int secs, poll;
  556 {
  557         int val;
  558 
  559         if (!poll) {
  560                 int s;
  561 
  562                 /* Not polling, can sleep. Sleep until we are awakened,
  563                  * but maximum secs seconds.
  564                  */
  565                 s = splbio();
  566                 if (sc->sc_stat != STAT_DONE)
  567                         (void) tsleep(sc, PRIBIO, "edcwcmd", secs * hz);
  568                 splx(s);
  569         }
  570 
  571         /* Wait until the command is completely finished */
  572         while((val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, BSR))
  573             & BSR_CMD_INPROGRESS) {
  574                 if (poll && (val & BSR_INTR))
  575                         edc_intr(sc);
  576         }
  577 }
  578  
  579 /*
  580  * Command controller to execute specified command on a device.
  581  */
  582 int
  583 edc_run_cmd(sc, cmd, devno, cmd_args, cmd_len, poll)
  584         struct edc_mca_softc *sc;
  585         int cmd;
  586         int devno;
  587         u_int16_t cmd_args[];
  588         int cmd_len, poll;
  589 {
  590         int i, error, tries;
  591         u_int16_t cmd0;
  592 
  593         sc->sc_stat = STAT_START;
  594 
  595         /* Do Attention Request for Command Request. */
  596         if ((error = edc_do_attn(sc, ATN_CMD_REQ, devno, 0)))
  597                 return (error);
  598 
  599         /*
  600          * Construct the command. The bits are like this:
  601          *
  602          * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
  603          *  \_/   0  0       1 0 \__/   \_____/      
  604          *    \    \__________/     \         \_ Command Code (see CMD_*)
  605          *     \              \      \__ Device: 0 common, 7 controller
  606          *      \              \__ Options: reserved, bit 10=cache bypass bit
  607          *       \_ Type: 00=2B, 01=4B, 10 and 11 reserved
  608          *
  609          * We always use device 0 or 1, so difference is made only by Command
  610          * Code, Command Options and command length.
  611          */
  612         cmd0 = ((cmd_len == 4) ? (CIFR_LONG_CMD) : 0)
  613                 | (devno <<  5)
  614                 | (cmd_args[0] << 8) | cmd;
  615         cmd_args[0] = cmd0;
  616         
  617         /*
  618          * Write word of CMD to the CIFR. This sets "Command
  619          * Interface Register Full (CMD IN)" in BSR. Once the attachment
  620          * detects it, it reads the word and clears CMD IN. This all should
  621          * be quite fast, so don't sleep in !poll case neither.
  622          */
  623         for(i=0; i < cmd_len; i++) {
  624                 bus_space_write_2(sc->sc_iot, sc->sc_ioh, CIFR,
  625                         htole16(cmd_args[i]));
  626                         
  627                 /* Wait until CMD IN is cleared. */
  628                 tries = 0;
  629                 for(; (bus_space_read_1(sc->sc_iot, sc->sc_ioh, BSR)
  630                     & BSR_CIFR_FULL) && tries < 10000 ; tries++)
  631                         delay(poll ? 1000 : 1);
  632                         ;
  633 
  634                 if (tries == 10000
  635                     && bus_space_read_1(sc->sc_iot, sc->sc_ioh, BSR)
  636                        & BSR_CIFR_FULL) {
  637                         printf("%s: device too slow to accept command %d\n",
  638                                 sc->sc_dev.dv_xname, cmd);
  639                         return (EIO);
  640                 }
  641         }
  642 
  643         /* Wait for command to complete, but maximum 15 seconds. */
  644         edc_cmd_wait(sc, 15, poll);
  645 
  646         return ((sc->sc_stat != STAT_DONE) ? EIO : 0);
  647 }
  648 
  649 #ifdef EDC_DEBUG
  650 static const char * const edc_commands[] = {
  651         "Invalid Command",
  652         "Read Data",
  653         "Write Data",
  654         "Read Verify",
  655         "Write with Verify",
  656         "Seek",
  657         "Park Head",
  658         "Get Command Complete Status",
  659         "Get Device Status",
  660         "Get Device Configuration",
  661         "Get POS Information",
  662         "Translate RBA",
  663         "Write Attachment Buffer",
  664         "Read Attachment Buffer",
  665         "Run Diagnostic Test",
  666         "Get Diagnostic Status Block",
  667         "Get MFG Header",
  668         "Format Unit",
  669         "Format Prepare",
  670         "Set MAX RBA",
  671         "Set Power Saving Mode",
  672         "Power Conservation Command",
  673 };
  674 
  675 static const char * const edc_cmd_status[256] = {
  676         "Reserved",
  677         "Command completed successfully",
  678         "Reserved",
  679         "Command completed successfully with ECC applied",
  680         "Reserved",
  681         "Command completed successfully with retries",
  682         "Format Command partially completed",   /* Status available */
  683         "Command completed successfully with ECC and retries",
  684         "Command completed with Warning",       /* Command Error is available */
  685         "Aborted",
  686         "Reset completed",
  687         "Data Transfer Ready",          /* No Status Block available */
  688         "Command terminated with failure",      /* Device Error is available */
  689         "DMA Error",                    /* Retry entire command as recovery */
  690         "Command Block Error",
  691         "Attention Error (Illegal Attention Code)",
  692         /* 0x14 - 0xff reserved */
  693 };
  694 
  695 static const char * const edc_cmd_error[256] = {
  696         "No Error",
  697         "Invalid parameter in the command block",
  698         "Reserved",
  699         "Command not supported",
  700         "Command Aborted per request",
  701         "Reserved",
  702         "Command rejected",     /* Attachment diagnostic failure */
  703         "Format Rejected",      /* Prepare Format command is required */
  704         "Format Error (Primary Map is not readable)",
  705         "Format Error (Secondary map is not readable)",
  706         "Format Error (Diagnostic Failure)",
  707         "Format Warning (Secondary Map Overflow)",
  708         "Reserved"
  709         "Format Error (Host Checksum Error)",
  710         "Reserved",
  711         "Format Warning (Push table overflow)",
  712         "Format Warning (More pushes than allowed)",
  713         "Reserved",
  714         "Format Warning (Error during verifying)",
  715         "Invalid device number for the command",
  716         /* 0x14-0xff reserved */
  717 };
  718 
  719 static const char * const edc_dev_errors[] = {
  720         "No Error",
  721         "Seek Fault",   /* Device report */
  722         "Interface Fault (Parity, Attn, or Cmd Complete Error)",
  723         "Block not found (ID not found)",
  724         "Block not found (AM not found)",
  725         "Data ECC Error (hard error)",
  726         "ID CRC Error",
  727         "RBA Out of Range",
  728         "Reserved",
  729         "Defective Block",
  730         "Reserved",
  731         "Selection Error",
  732         "Reserved",
  733         "Write Fault",
  734         "No index or sector pulse",
  735         "Device Not Ready",
  736         "Seek Error",   /* Attachment report */
  737         "Bad Format",
  738         "Volume Overflow",
  739         "No Data AM Found",
  740         "Block not found (No ID AM or ID CRC error occurred)",
  741         "Reserved",
  742         "Reserved",
  743         "No ID found on track (ID search)",
  744         /* 0x19 - 0xff reserved */
  745 };
  746 #endif /* EDC_DEBUG */
  747 
  748 static void
  749 edc_dump_status_block(sc, status_block, intr_id)
  750         struct edc_mca_softc *sc;
  751         u_int16_t *status_block;
  752         int intr_id;
  753 {
  754 #ifdef EDC_DEBUG
  755         printf("%s: Command: %s, Status: %s (intr %d)\n",
  756                 sc->sc_dev.dv_xname,
  757                 edc_commands[status_block[0] & 0x1f],
  758                 edc_cmd_status[SB_GET_CMD_STATUS(status_block)],
  759                 intr_id
  760                 );
  761 #else
  762         printf("%s: Command: %d, Status: %d (intr %d)\n",
  763                 sc->sc_dev.dv_xname,
  764                 status_block[0] & 0x1f,
  765                 SB_GET_CMD_STATUS(status_block),
  766                 intr_id
  767                 );
  768 #endif
  769         printf("%s: # left blocks: %u, last processed RBA: %u\n",
  770                 sc->sc_dev.dv_xname,
  771                 status_block[SB_RESBLKCNT_IDX],
  772                 (status_block[5] << 16) | status_block[4]);
  773 
  774         if (intr_id == ISR_COMPLETED_WARNING) {
  775 #ifdef EDC_DEBUG
  776                 printf("%s: Command Error Code: %s\n",
  777                         sc->sc_dev.dv_xname,
  778                         edc_cmd_error[status_block[1] & 0xff]);
  779 #else
  780                 printf("%s: Command Error Code: %d\n",
  781                         sc->sc_dev.dv_xname,
  782                         status_block[1] & 0xff);
  783 #endif
  784         }
  785 
  786         if (intr_id == ISR_CMD_FAILED) {
  787 #ifdef EDC_DEBUG
  788                 char buf[100];
  789 
  790                 printf("%s: Device Error Code: %s\n",
  791                         sc->sc_dev.dv_xname,
  792                         edc_dev_errors[status_block[2] & 0xff]);
  793                 bitmask_snprintf((status_block[2] & 0xff00) >> 8,
  794                         "\2"
  795                         "\01SeekOrCmdComplete"
  796                         "\02Track0Flag"
  797                         "\03WriteFault"
  798                         "\04Selected"
  799                         "\05Ready"
  800                         "\06Reserved0"
  801                         "\07STANDBY"
  802                         "\010Reserved0",
  803                         buf, sizeof(buf));
  804                 printf("%s: Device Status: %s\n",
  805                         sc->sc_dev.dv_xname, buf);
  806 #else
  807                 printf("%s: Device Error Code: %d, Device Status: %d\n",
  808                         sc->sc_dev.dv_xname,
  809                         status_block[2] & 0xff,
  810                         (status_block[2] & 0xff00) >> 8);
  811 #endif
  812         }
  813 }
  814 
  815 static void
  816 edc_spawn_worker(arg)
  817         void *arg;
  818 {
  819         struct edc_mca_softc *sc = (struct edc_mca_softc *) arg;
  820         int error;
  821         struct proc *wrk;
  822 
  823         /* Now, everything is ready, start a kthread */
  824         if ((error = kthread_create1(edcworker, sc, &wrk,
  825                         "%s", sc->sc_dev.dv_xname))) {
  826                 printf("%s: cannot spawn worker thread: errno=%d\n",
  827                         sc->sc_dev.dv_xname, error);
  828                 panic("edc_spawn_worker");
  829         }
  830 }
  831 
  832 /*
  833  * Main worker thread function.
  834  */
  835 void
  836 edcworker(arg)
  837         void *arg;
  838 {
  839         struct edc_mca_softc *sc = (struct edc_mca_softc *) arg;
  840         struct ed_softc *ed;
  841         struct buf *bp;
  842         int i, error;
  843 
  844         config_pending_decr();
  845 
  846         for(;;) {
  847                 /* Wait until awakened */
  848                 (void) tsleep(sc, PRIBIO, "edcidle", 0);
  849 
  850                 for(i=0; i<sc->sc_maxdevs; ) {
  851                         if ((ed = sc->sc_ed[i]) == NULL) {
  852                                 i++;
  853                                 continue;
  854                         }
  855 
  856                         /* Is there a buf for us ? */
  857                         simple_lock(&ed->sc_q_lock);
  858                         if ((bp = BUFQ_GET(&ed->sc_q)) == NULL) {
  859                                 simple_unlock(&ed->sc_q_lock);
  860                                 i++;
  861                                 continue;
  862                         }
  863                         simple_unlock(&ed->sc_q_lock);
  864 
  865                         /* Instrumentation. */
  866                         disk_busy(&ed->sc_dk);
  867         
  868                         error = edc_bio(sc, ed, bp->b_data, bp->b_bcount,
  869                                 bp->b_rawblkno, (bp->b_flags & B_READ), 0);
  870 
  871                         if (error) {
  872                                 bp->b_error = error;
  873                                 bp->b_flags |= B_ERROR;
  874                         } else {
  875                                 /* Set resid, most commonly to zero. */
  876                                 bp->b_resid = sc->sc_resblk * DEV_BSIZE;
  877                         }
  878 
  879                         disk_unbusy(&ed->sc_dk, (bp->b_bcount - bp->b_resid),
  880                             (bp->b_flags & B_READ));
  881 #if NRND > 0
  882                         rnd_add_uint32(&ed->rnd_source, bp->b_blkno);
  883 #endif
  884                         biodone(bp);
  885                 }
  886         }
  887 }
  888 
  889 int
  890 edc_bio(struct edc_mca_softc *sc, struct ed_softc *ed, void *data,
  891         size_t bcount, daddr_t rawblkno, int isread, int poll)
  892 {
  893         u_int16_t cmd_args[4];
  894         int error=0, fl;
  895         u_int16_t track;
  896         u_int16_t cyl;
  897         u_int8_t head;
  898         u_int8_t sector;
  899 
  900         mca_disk_busy();
  901 
  902         /* set WAIT and R/W flag appropriately for the DMA transfer */
  903         fl = ((poll) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK)
  904                 | ((isread) ? BUS_DMA_READ : BUS_DMA_WRITE);
  905 
  906         /* Load the buffer for DMA transfer. */
  907         if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap_xfer, data,
  908             bcount, NULL, BUS_DMA_STREAMING|fl))) {
  909                 printf("%s: ed_bio: unable to load DMA buffer - error %d\n",
  910                         ed->sc_dev.dv_xname, error);
  911                 goto out;
  912         }
  913 
  914         bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_xfer, 0,
  915                 bcount, (isread) ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
  916         
  917         track = rawblkno / ed->sectors;
  918         head = track % ed->heads;
  919         cyl = track / ed->heads;
  920         sector = rawblkno % ed->sectors;
  921 
  922         /* Read or Write Data command */
  923         cmd_args[0] = 2;        /* Options 0000010 */
  924         cmd_args[1] = bcount / DEV_BSIZE;
  925         cmd_args[2] = ((cyl & 0x1f) << 11) | (head << 5) | sector;
  926         cmd_args[3] = ((cyl & 0x3E0) >> 5);
  927         error = edc_run_cmd(sc,
  928                         (isread) ? CMD_READ_DATA : CMD_WRITE_DATA,
  929                         ed->sc_devno, cmd_args, 4, poll);
  930 
  931         /* Sync the DMA memory */
  932         if (!error)  {
  933                 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_xfer, 0, bcount,
  934                         (isread)? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
  935         }
  936 
  937         /* We are done, unload buffer from DMA map */
  938         bus_dmamap_unload(sc->sc_dmat, sc->sc_dmamap_xfer);
  939 
  940     out:
  941         mca_disk_unbusy();
  942 
  943         return (error);
  944 }

Cache object: f4d41f02f8838251b101f34d81c5621c


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