Annotation of Gnu-Mach/i386/i386at/nhd.c, revision 1.1.1.1

1.1       root        1: /* 
                      2:  * Copyright (c) 1994 Shantanu Goel
                      3:  * All Rights Reserved.
                      4:  * 
                      5:  * Permission to use, copy, modify and distribute this software and its
                      6:  * documentation is hereby granted, provided that both the copyright
                      7:  * notice and this permission notice appear in all copies of the
                      8:  * software, derivative works or modified versions, and any portions
                      9:  * thereof, and that both notices appear in supporting documentation.
                     10:  * 
                     11:  * THE AUTHOR ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
                     12:  * CONDITION.  THE AUTHOR DISCLAIMS ANY LIABILITY OF ANY KIND FOR
                     13:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
                     14:  *
                     15:  * MODIFIED BY KEVIN T. VAN MAREN, University of Utah, CSL
                     16:  * Copyright (c) 1996, University of Utah, CSL
                     17:  *
                     18:  * Uses a 'unified' partition code with the SCSI driver.
                     19:  * Reading/Writing disklabels through the kernel is NOT recommended.
                     20:  * (The preferred method is through the raw device (wd0), with no
                     21:  * open partitions).  setdisklabel() should work for the in-core
                     22:  * fudged disklabel, but will not change the partitioning. The driver
                     23:  * *never* sees the disklabel on the disk.
                     24:  *
                     25:  */
                     26: 
                     27: 
                     28: #include <hd.h>
                     29: #if NHD > 0 && !defined(LINUX_DEV)
                     30: /*
                     31:  * Hard disk driver.
                     32:  *
                     33:  * Supports:
                     34:  * 1 controller and 2 drives.
                     35:  * Arbitrarily sized read/write requests.
                     36:  * Misaligned requests.
                     37:  * Multiple sector transfer mode (not tested extensively).
                     38:  *
                     39:  * TODO:
                     40:  * 1) Real probe routines for controller and drives.
                     41:  * 2) Support for multiple controllers.  The driver does
                     42:  * not assume a single controller since all functions
                     43:  * take the controller and/or device structure as an
                     44:  * argument, however the probe routines limit the
                     45:  * number of controllers and drives to 1 and 2 respectively.
                     46:  *
                     47:  * Shantanu Goel ([email protected])
                     48:  */
                     49: #include <sys/types.h>
                     50: #include <sys/ioctl.h>
                     51: #include "vm_param.h"
                     52: #include <kern/time_out.h>
                     53: #include <vm/vm_kern.h>
                     54: #include <vm/pmap.h>
                     55: #include <device/param.h>
                     56: #include <device/buf.h>
                     57: #include <device/errno.h>
                     58: #include <device/device_types.h>
                     59: #include <device/disk_status.h>
                     60: #include <chips/busses.h>
                     61: #include <i386/machspl.h>
                     62: #include <i386/pio.h>
                     63: #include <i386at/cram.h>
                     64: #include <i386at/disk.h>
                     65: #include <i386at/nhdreg.h>
                     66: 
                     67: #include <scsi/rz_labels.h>
                     68: 
                     69: 
                     70: /* this is for the partition code */
                     71: typedef struct ide_driver_info {
                     72:        dev_t dev;
                     73: /*     struct buf *bp; */
                     74:        int sectorsize;
                     75: } ide_driver_info;
                     76: 
                     77: #define MAX_IDE_PARTS 32   /* max partitions per drive */
                     78: static char *drive_name[4]={"wd0: ","wd1: ","xxx ","yyy "};
                     79: 
                     80: /*
                     81:  * XXX: This will have to be fixed for controllers that
                     82:  * can support upto 4 drives.
                     83:  */
                     84: #define NDRIVES_PER_HDC        2
                     85: #define NHDC           ((NHD + NDRIVES_PER_HDC - 1) / NDRIVES_PER_HDC)
                     86: 
                     87: #define b_cylin                b_resid
                     88: 
                     89: #define B_ABS          B_MD1
                     90: #define B_IDENTIFY     (B_MD1 << 1)
                     91: 
                     92: /* shift right SLICE_BITS + PARTITION_BITS. Note: 2^10 = 1024 sub-parts */
                     93: #define hdunit(dev)    (((dev) >> 10) & 3)
                     94: #define hdpart(dev)    ((dev) & 0x3ff)
                     95: 
                     96: #define MAX_RETRIES    12      /* maximum number of retries */
                     97: #define OP_TIMEOUT     7       /* time to wait (secs) for an operation */
                     98: 
                     99: /*
                    100:  * Autoconfiguration stuff.
                    101:  */
                    102: struct bus_ctlr *hdminfo[NHDC];
                    103: struct bus_device *hddinfo[NHD];
                    104: int    hdstd[] = { 0 };
                    105: int    hdprobe(), hdslave(), hdstrategy();
                    106: void   hdattach();
                    107: struct bus_driver hddriver = {
                    108:        hdprobe, hdslave, hdattach, 0, hdstd, "hd", hddinfo, "hdc", hdminfo, 0
                    109: };
                    110: 
                    111: /*
                    112:  * BIOS geometry.
                    113:  */
                    114: struct hdbios {
                    115:        int     bg_ncyl;        /* cylinders/unit */
                    116:        int     bg_ntrk;        /* tracks/cylinder */
                    117:        int     bg_precomp;     /* write precomp cylinder */
                    118:        int     bg_nsect;       /* sectors/track */
                    119: } hdbios[NHD];
                    120: 
                    121: /*
                    122:  * Controller state.
                    123:  */
                    124: struct hdcsoftc {
                    125:        int     sc_state;       /* transfer fsm */
                    126:        caddr_t sc_addr;        /* buffer address */
                    127:        int     sc_resid;       /* amount left to transfer */
                    128:        int     sc_amt;         /* amount currently being transferred */
                    129:        int     sc_cnt;         /* amount transferred per interrupt */
                    130:        int     sc_sn;          /* sector number */
                    131:        int     sc_tn;          /* track number */
                    132:        int     sc_cn;          /* cylinder number */
                    133:        int     sc_recalerr;    /* # recalibration errors */
                    134:        int     sc_ioerr;       /* # i/o errors */
                    135:        int     sc_wticks;      /* watchdog */
                    136:        caddr_t sc_buf;         /* buffer for unaligned requests */
                    137: } hdcsoftc[NHDC];
                    138: 
                    139: /*
                    140:  * Transfer states.
                    141:  */
                    142: #define IDLE           0       /* controller is idle */
                    143: #define SETPARAM       1       /* set disk parameters */
                    144: #define SETPARAMDONE   2       /* set parameters done */
                    145: #define RESTORE                3       /* recalibrate drive */
                    146: #define RESTOREDONE    4       /* recalibrate done */
                    147: #define TRANSFER       5       /* perform I/O transfer */
                    148: #define TRANSFERDONE   6       /* transfer done */
                    149: #define IDENTIFY       7       /* get drive info */
                    150: #define IDENTIFYDONE   8       /* get drive info done */
                    151: #define SETMULTI       9       /* set multiple mode count */
                    152: #define SETMULTIDONE   10      /* set multiple mode count done */
                    153: 
                    154: /*
                    155:  * Drive state.
                    156:  */
                    157: struct hdsoftc {
                    158:        int     sc_flags;
                    159: #define HDF_SETPARAM   0x001   /* set drive parameters before I/O operation */
                    160: #define HDF_RESTORE    0x002   /* drive needs recalibration */
                    161: #define HDF_WANT       0x004   /* some one is waiting for drive */
                    162: #define HDF_UNALIGNED  0x008   /* request is not a multiple of sector size */
                    163: #define HDF_SETMULTI   0x010   /* set multiple count before I/O operation */
                    164: #define HDF_MULTIDONE  0x020   /* multicnt field is valid */
                    165: #define HDF_IDENTDONE  0x040   /* identify command done */
                    166: #define HDF_LBA                0x080   /* use LBA mode */
                    167:        int     sc_multicnt;    /* current multiple count */
                    168:        int     sc_abssn;       /* absolute sector number (for {RD,WR}ABS) */
                    169:        int     sc_abscnt;      /* absolute sector count */
                    170:        int     sc_openpart;    /* bit mask of open partitions */
                    171:        struct  hdident sc_id;  /* info returned by identify */
                    172: } hdsoftc[NHD];
                    173: 
                    174: struct buf hdtab[NHDC];        /* controller queues */
                    175: struct buf hdutab[NHD];        /* drive queues */
                    176: struct disklabel hdlabel[NHD]; /* disklabels -- incorrect info! */
                    177: struct  diskpart array[NHD*MAX_IDE_PARTS]; /* partition info */
                    178: 
                    179: /*
                    180:  * To enable multiple mode,
                    181:  * set this, recompile, and reboot the machine.
                    182:  */
                    183: int    hdenmulti = 0;
                    184: 
                    185: char   *hderrchk();
                    186: struct buf *geteblk();
                    187: int    hdwstart = 0;
                    188: void   hdwatch();
                    189: 
                    190: /*
                    191:  * Probe for a controller.
                    192:  */
                    193: int
                    194: hdprobe(xxx, um)
                    195:        int xxx;
                    196:        struct bus_ctlr *um;
                    197: {
                    198:        struct hdcsoftc *hdc;
                    199: 
                    200:        if (um->unit >= NHDC) {
                    201:                printf("hdc%d: not configured\n", um->unit);
                    202:                return (0);
                    203:        }
                    204:        if (um->unit > 0) {     /* XXX: only 1 controller */
                    205: 
                    206:                 printf("nhd:probe for 2+ controllers -- not implemented\n");
                    207:                 return (0);
                    208:         }
                    209: 
                    210:        /*
                    211:         * XXX: need real probe
                    212:        */
                    213:        hdc = &hdcsoftc[um->unit];
                    214:        if (!hdc->sc_buf)
                    215:                kmem_alloc(kernel_map,
                    216:                           (vm_offset_t *)&hdc->sc_buf, I386_PGBYTES);
                    217:        take_ctlr_irq(um);
                    218:        return (1);
                    219: }
                    220: 
                    221: /*
                    222:  * Probe for a drive.
                    223:  */
                    224: int
                    225: hdslave(ui)
                    226:        struct bus_device *ui;
                    227: {
                    228:        int type;
                    229: 
                    230:        if (ui->unit >= NHD) {
                    231:                printf("hd%d: not configured\n", ui->unit);
                    232:                return (0);
                    233:        }
                    234:        if (ui->unit > 1)       /* XXX: only 2 drives */
                    235:                return (0);
                    236: 
                    237:        /*
                    238:         * Find out if drive exists by reading CMOS.
                    239:         */
                    240:        outb(CMOS_ADDR, 0x12);
                    241:        type = inb(CMOS_DATA);
                    242:        if (ui->unit == 0)
                    243:                type >>= 4;
                    244:        type &= 0x0f;
                    245:        return (type);
                    246: }
                    247: 
                    248: /*
                    249:  * Attach a drive to the system.
                    250:  */
                    251: void
                    252: hdattach(ui)
                    253:        struct bus_device *ui;
                    254: {
                    255:        char *tbl;
                    256:        unsigned n;
                    257:        /* struct hdsoftc *sc = &hdsoftc[ui->unit]; */
                    258:        struct disklabel *lp = &hdlabel[ui->unit];
                    259:        struct hdbios *bg = &hdbios[ui->unit];
                    260: 
                    261:        /*
                    262:         * Set up a temporary disklabel from BIOS parameters.
                    263:         * The actual partition table will be read during open.
                    264:         */
                    265:        n = *(unsigned *)phystokv(ui->address);
                    266:        tbl = (unsigned char *)phystokv((n & 0xffff) + ((n >> 12) & 0xffff0));
                    267:        bg->bg_ncyl = *(unsigned short *)tbl;
                    268:        bg->bg_ntrk = *(unsigned char *)(tbl + 2);
                    269:        bg->bg_precomp = *(unsigned short *)(tbl + 5);
                    270:        bg->bg_nsect = *(unsigned char *)(tbl + 14);
                    271:        fudge_bsd_label(lp, DTYPE_ESDI, bg->bg_ncyl*bg->bg_ntrk*bg->bg_nsect,
                    272:                        bg->bg_ntrk, bg->bg_nsect, SECSIZE, 3);  
                    273: 
                    274:        /* FORCE sector size to 512... */
                    275: 
                    276:        printf(": ntrak(heads) %d, ncyl %d, nsec %d, size %u MB",
                    277:               lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors,
                    278:               lp->d_secperunit * lp->d_secsize / (1024*1024));
                    279: }
                    280: 
                    281: int
                    282: hdopen(dev, mode)
                    283:        dev_t dev;
                    284:        int mode;
                    285: {
                    286:        int unit = hdunit(dev), part = hdpart(dev) /*, error */;
                    287:        struct bus_device *ui;
                    288:        struct hdsoftc *sc;
                    289:        struct diskpart *label;
                    290: 
                    291:        if (unit >= NHD || (ui = hddinfo[unit]) == 0 || ui->alive == 0)
                    292:                return (ENXIO);
                    293:        if (!hdwstart) {
                    294:                hdwstart++;
                    295:                timeout(hdwatch, 0, hz);
                    296:        }
                    297:        sc = &hdsoftc[unit];
                    298:        /* should this be changed so only gets called once, even if all 
                    299:           partitions are closed and re-opened? */
                    300:        if (sc->sc_openpart == 0) {
                    301:                hdinit(dev);
                    302:                if (sc->sc_flags & HDF_LBA)
                    303:                        printf("hd%d: Using LBA mode\n", ui->unit);
                    304:        }
                    305: 
                    306: /* Note: should set a bit in the label structure to ensure that
                    307:    aliasing prevents multiple instances to be opened. */
                    308: #if 0
                    309:        if (part >= MAXPARTITIONS || lp->d_partitions[part].p_size == 0)
                    310:                return (ENXIO);
                    311: #endif 0
                    312: 
                    313:        label=lookup_part(&array[MAX_IDE_PARTS*unit], hdpart(dev));
                    314:        if (!label)
                    315:                return (ENXIO);
                    316: 
                    317: 
                    318:        sc->sc_openpart |= 1 << part;
                    319:        return (0);
                    320: }
                    321: 
                    322: int
                    323: hdclose(dev)
                    324:        dev_t dev;
                    325: {
                    326:        int unit = hdunit(dev), s;
                    327:        struct hdsoftc *sc = &hdsoftc[unit];
                    328: 
                    329:        sc->sc_openpart &= ~(1 << hdpart(dev));
                    330:        if (sc->sc_openpart == 0) {
                    331:                s = splbio();
                    332:                while (hdutab[unit].b_active) {
                    333:                        sc->sc_flags |= HDF_WANT;
                    334:                        assert_wait((event_t)sc, FALSE);
                    335:                        thread_block((void (*)())0);
                    336:                }
                    337:                splx(s);
                    338:        }
                    339:        return (0);
                    340: }
                    341: 
                    342: int
                    343: hdread(dev, ior)
                    344:        dev_t dev;
                    345:        io_req_t ior;
                    346: {
                    347:        return (block_io(hdstrategy, minphys, ior));
                    348: }
                    349: 
                    350: int
                    351: hdwrite(dev, ior)
                    352:        dev_t dev;
                    353:        io_req_t ior;
                    354: {
                    355:        return (block_io(hdstrategy, minphys, ior));
                    356: }
                    357: 
                    358: int
                    359: hdgetstat(dev, flavor, data, count)
                    360:        dev_t dev;
                    361:        dev_flavor_t flavor;
                    362:        dev_status_t data;
                    363:        mach_msg_type_number_t *count;
                    364: {
                    365:        int unit = hdunit(dev), part = hdpart(dev);
                    366:        struct hdsoftc *sc = &hdsoftc[unit];
                    367:        struct disklabel *lp = &hdlabel[unit];
                    368:        struct buf *bp;
                    369:        struct diskpart *label;
                    370: 
                    371:        label=lookup_part(&array[MAX_IDE_PARTS*unit], hdpart(dev));
                    372:        switch (flavor) {
                    373: 
                    374:        case DEV_GET_SIZE:
                    375:                if (label) {
                    376:                        data[DEV_GET_SIZE_DEVICE_SIZE] = (label->size * lp->d_secsize);
                    377:                        data[DEV_GET_SIZE_RECORD_SIZE] = lp->d_secsize;
                    378:                        *count = DEV_GET_SIZE_COUNT;
                    379:                } else {  /* Kevin: added checking here */
                    380:                        data[DEV_GET_SIZE_DEVICE_SIZE] = 0;
                    381:                        data[DEV_GET_SIZE_RECORD_SIZE] = 0;
                    382:                        *count = 0;
                    383:                }
                    384:                break;
                    385: 
                    386:        case DIOCGDINFO:
                    387:        case DIOCGDINFO - (0x10 << 16):
                    388:                dkgetlabel(lp, flavor, data, count);
                    389:                break;
                    390: 
                    391:        case V_GETPARMS:
                    392:        {
                    393:                struct disk_parms *dp;
                    394:                struct hdbios *bg = &hdbios[unit];
                    395: 
                    396:                if (*count < (sizeof(struct disk_parms) / sizeof(int)))
                    397:                        return (D_INVALID_OPERATION);
                    398:                dp = (struct disk_parms *)data;
                    399:                dp->dp_type = DPT_WINI;
                    400:                dp->dp_heads = lp->d_ntracks;
                    401:                dp->dp_cyls = lp->d_ncylinders;
                    402:                dp->dp_sectors = lp->d_nsectors;
                    403:                dp->dp_dosheads = bg->bg_ntrk;
                    404:                dp->dp_doscyls = bg->bg_ncyl;
                    405:                dp->dp_dossectors = bg->bg_nsect;
                    406:                dp->dp_secsiz = lp->d_secsize;
                    407:                dp->dp_ptag = 0;
                    408:                dp->dp_pflag = 0;
                    409:                if (label) {
                    410:                        dp->dp_pstartsec = label->start;
                    411:                        dp->dp_pnumsec = label->size; 
                    412:                } else { /* added by Kevin */
                    413:                        dp->dp_pstartsec = -1;
                    414:                        dp->dp_pnumsec = -1;
                    415:                }
                    416: 
                    417:                *count = sizeof(struct disk_parms) / sizeof(int);
                    418:                break;
                    419:        }
                    420:        case V_RDABS:
                    421:                if (*count < lp->d_secsize / sizeof(int)) {
                    422:                        printf("hd%d: RDABS, bad size %d\n", unit, *count);
                    423:                        return (EINVAL);
                    424:                }
                    425:                bp = geteblk(lp->d_secsize);
                    426:                bp->b_flags = B_READ | B_ABS;
                    427:                bp->b_blkno = sc->sc_abssn;
                    428:                bp->b_dev = dev;
                    429:                bp->b_bcount = lp->d_secsize;
                    430:                hdstrategy(bp);
                    431:                biowait(bp);
                    432:                if (bp->b_flags & B_ERROR) {
                    433:                        printf("hd%d: RDABS failed\n", unit);
                    434:                        brelse(bp);
                    435:                        return (EIO);
                    436:                }
                    437:                bcopy(bp->b_un.b_addr, (caddr_t)data, lp->d_secsize);
                    438:                brelse(bp);
                    439:                *count = lp->d_secsize / sizeof(int);
                    440:                break;
                    441: 
                    442:        case V_VERIFY:
                    443:        {
                    444:                int i, amt, n, error = 0;
                    445: 
                    446:                bp = geteblk(I386_PGBYTES);
                    447:                bp->b_blkno = sc->sc_abssn;
                    448:                bp->b_dev = dev;
                    449:                amt = sc->sc_abscnt;
                    450:                n = I386_PGBYTES / lp->d_secsize;
                    451:                while (amt > 0) {
                    452:                        i = (amt > n) ? n : amt;
                    453:                        bp->b_bcount = i * lp->d_secsize;
                    454:                        bp->b_flags = B_READ | B_ABS;
                    455:                        hdstrategy(bp);
                    456:                        biowait(bp);
                    457:                        if (bp->b_flags & B_ERROR) {
                    458:                                error = BAD_BLK;
                    459:                                break;
                    460:                        }
                    461:                        amt -= bp->b_bcount;
                    462:                        bp->b_blkno += i;
                    463:                }
                    464:                brelse(bp);
                    465:                data[0] = error;
                    466:                *count = 1;
                    467:                break;
                    468:        }
                    469:        default:
                    470:                return (D_INVALID_OPERATION);
                    471:        }
                    472:        return (0);
                    473: }
                    474: 
                    475: int
                    476: hdsetstat(dev, flavor, data, count)
                    477:        dev_t dev;
                    478:        dev_flavor_t flavor;
                    479:        dev_status_t data;
                    480:        mach_msg_type_number_t count;
                    481: {
                    482:        int unit = hdunit(dev); /* , part = hdpart(dev); */
                    483:        int error = 0 /*, s */;
                    484:        struct hdsoftc *sc = &hdsoftc[unit];
                    485:        struct disklabel *lp = &hdlabel[unit];
                    486:        struct buf *bp;
                    487: 
                    488:        switch (flavor) {
                    489: 
                    490:        case DIOCWLABEL:
                    491:        case DIOCWLABEL - (0x10 << 16):
                    492:                break;
                    493: 
                    494:        case DIOCSDINFO:
                    495:        case DIOCSDINFO - (0x10 << 16):
                    496:                if (count != (sizeof(struct disklabel) / sizeof(int)))
                    497:                        return (D_INVALID_SIZE);
                    498:                error = setdisklabel(lp, (struct disklabel *)data);
                    499:                if (error == 0 && (sc->sc_flags & HDF_LBA) == 0)
                    500:                        sc->sc_flags |= HDF_SETPARAM;
                    501:                break;
                    502: 
                    503:        case DIOCWDINFO:
                    504:        case DIOCWDINFO - (0x10 << 16):
                    505:                if (count != (sizeof(struct disklabel) / sizeof(int)))
                    506:                        return (D_INVALID_SIZE);
                    507:                error = setdisklabel(lp, (struct disklabel *)data);
                    508:                if (error == 0) {
                    509:                        if ((sc->sc_flags & HDF_LBA) == 0)
                    510:                                sc->sc_flags |= HDF_SETPARAM;
                    511:                        error = hdwritelabel(dev);
                    512:                }
                    513:                break;
                    514: 
                    515:        case V_REMOUNT:
                    516:                hdinit(dev);
                    517:                break;
                    518: 
                    519:        case V_ABS:
                    520:                if (count != 1 && count != 2)
                    521:                        return (D_INVALID_OPERATION);
                    522:                sc->sc_abssn = *(int *)data;
                    523:                if (sc->sc_abssn < 0 || sc->sc_abssn >= lp->d_secperunit)
                    524:                        return (D_INVALID_OPERATION);
                    525:                if (count == 2)
                    526:                        sc->sc_abscnt = *((int *)data + 1);
                    527:                else
                    528:                        sc->sc_abscnt = 1;
                    529:                if (sc->sc_abscnt <= 0
                    530:                    || sc->sc_abssn + sc->sc_abscnt > lp->d_secperunit)
                    531:                        return (D_INVALID_OPERATION);
                    532:                break;
                    533: 
                    534:        case V_WRABS:
                    535:                if (count < (lp->d_secsize / sizeof(int))) {
                    536:                        printf("hd%d: WRABS, bad size %d\n", unit, count);
                    537:                        return (D_INVALID_OPERATION);
                    538:                }
                    539:                bp = geteblk(lp->d_secsize);
                    540:                bcopy((caddr_t)data, bp->b_un.b_addr, lp->d_secsize);
                    541:                bp->b_flags = B_WRITE | B_ABS;
                    542:                bp->b_blkno = sc->sc_abssn;
                    543:                bp->b_bcount = lp->d_secsize;
                    544:                bp->b_dev = dev;
                    545:                hdstrategy(bp);
                    546:                biowait(bp);
                    547:                if (bp->b_flags & B_ERROR) {
                    548:                        printf("hd%d: WRABS failed\n", unit);
                    549:                        error = EIO;
                    550:                }
                    551:                brelse(bp);
                    552:                break;
                    553: 
                    554:        default:
                    555:                return (D_INVALID_OPERATION);
                    556:        }
                    557:        return (error);
                    558: }
                    559: 
                    560: int
                    561: hddevinfo(dev, flavor, info)
                    562:        dev_t dev;
                    563:        int flavor;
                    564:        char *info;
                    565: {
                    566:        switch (flavor) {
                    567: 
                    568:        case D_INFO_BLOCK_SIZE:
                    569:                *((int *)info) = SECSIZE;  /* #defined to 512 */
                    570:                break;
                    571: 
                    572:        default:
                    573:                return (D_INVALID_OPERATION);
                    574:        }
                    575:        return (0);
                    576: }
                    577: 
                    578: 
                    579: 
                    580: 
                    581: /* Kevin T. Van Maren: Added this low-level routine for the unified 
                    582:    partition code. A pointer to this routine is passed, along with param* */
                    583: int 
                    584: ide_read_fun(struct ide_driver_info *param, int sectornum, char *buff) 
                    585: {
                    586:        struct buf *bp;
                    587: 
                    588:        bp = geteblk(param->sectorsize);
                    589:        bp->b_flags =  B_READ | B_ABS;
                    590: 
                    591:         bp->b_bcount = param->sectorsize;
                    592:         bp->b_blkno = sectornum;
                    593: 
                    594:        /* WARNING: DEPENDS ON NUMBER OF BITS FOR PARTITIONS */
                    595:        bp->b_dev = param->dev & ~0x3ff;
                    596:        hdstrategy(bp);
                    597:        biowait(bp);
                    598:        if ((bp->b_flags & B_ERROR) == 0) 
                    599:                bcopy((char *)bp->b_un.b_addr, buff, param->sectorsize);
                    600:        else {
                    601:                printf("ERROR!\n");
                    602:                return(B_ERROR);
                    603:        }
                    604: 
                    605:        brelse(bp);
                    606:        return(0);
                    607: }
                    608: 
                    609: 
                    610: 
                    611: /*
                    612:  * Initialize drive.
                    613:  */
                    614: int
                    615: hdinit(dev)
                    616:        dev_t dev;
                    617: {
                    618:        int unit = hdunit(dev);
                    619:        struct hdsoftc *sc = &hdsoftc[unit];
                    620:        struct disklabel *lp = &hdlabel[unit], *dlp;
                    621:        struct buf *bp = 0;
                    622:        int numpart;
                    623: 
                    624:         struct ide_driver_info ide_param = { dev, /* bp, */ lp->d_secsize };
                    625:        int ret;
                    626: 
                    627:        /*
                    628:         * Issue identify command.
                    629:         */
                    630:        if ((sc->sc_flags & HDF_IDENTDONE) == 0) {
                    631:                sc->sc_flags |= HDF_IDENTDONE;
                    632:                bp = geteblk(lp->d_secsize);
                    633:                /* sector size #defined to 512 */
                    634:                bp->b_flags = B_IDENTIFY;
                    635:                bp->b_dev = dev;
                    636:                hdstrategy(bp);
                    637:                biowait(bp);
                    638:                if ((bp->b_flags & B_ERROR) == 0) {
                    639:                        bcopy((char *)bp->b_un.b_addr,
                    640:                              (char *)&sc->sc_id, sizeof(struct hdident));
                    641: 
                    642:                        /*
                    643:                         * Check if drive supports LBA mode.
                    644:                         */
                    645:                        if (sc->sc_id.id_capability & 2)
                    646:                                sc->sc_flags |= HDF_LBA;
                    647:                }
                    648:        }
                    649: 
                    650:        /*
                    651:         * Check if drive supports multiple read/write mode.
                    652:         */
                    653:        hdmulti(dev);
                    654: 
                    655:        /* Note: label was fudged during attach! */
                    656: 
                    657:        /* ensure the 'raw disk' can be accessed reliably */
                    658:         array[MAX_IDE_PARTS*unit].start=0;
                    659:         array[MAX_IDE_PARTS*unit].size=lp->d_secperunit;  /* fill in root for MY reads */
                    660: #if 0
                    661:         array[MAX_IDE_PARTS*unit].subs=0;
                    662:         array[MAX_IDE_PARTS*unit].nsubs=0; 
                    663:         array[MAX_IDE_PARTS*unit].type=0;
                    664:         array[MAX_IDE_PARTS*unit].fsys=0;
                    665: #endif 0
                    666: 
                    667:        numpart=get_only_partition(&ide_param, (*ide_read_fun),
                    668:                &array[MAX_IDE_PARTS*unit],MAX_IDE_PARTS,lp->d_secperunit, 
                    669:                drive_name[unit]);
                    670: 
                    671:        printf("%s %d partitions found\n",drive_name[unit],numpart);
                    672: 
                    673:         if ((sc->sc_flags & HDF_LBA) == 0)
                    674:                 sc->sc_flags |= HDF_SETPARAM;
                    675: 
                    676:         brelse(bp);
                    677:        return(ret);
                    678: }
                    679: 
                    680: 
                    681: 
                    682: 
                    683: /*
                    684:  * Check if drive supports multiple read/write mode.
                    685:  */
                    686: int
                    687: hdmulti(dev)
                    688:        dev_t dev;
                    689: {
                    690:        int unit = hdunit(dev);
                    691:        struct hdsoftc *sc = &hdsoftc[unit];
                    692:        struct buf *bp;
                    693:        struct hdident *id;
                    694: 
                    695:        if (sc->sc_flags & HDF_MULTIDONE)
                    696:                return(0);
                    697: 
                    698:        sc->sc_flags |= HDF_MULTIDONE;
                    699: 
                    700:        if (hdenmulti == 0)
                    701:                return(0);
                    702: 
                    703:        /*
                    704:         * Get drive information by issuing IDENTIFY command.
                    705:         */
                    706:        bp = geteblk(DEV_BSIZE);
                    707:        bp->b_flags = B_IDENTIFY;
                    708:        bp->b_dev = dev;
                    709:        hdstrategy(bp);
                    710:        biowait(bp);
                    711:        id = (struct hdident *)bp->b_un.b_addr;
                    712: 
                    713:        /*
                    714:         * If controller does not recognise IDENTIFY command,
                    715:         * or does not support multiple mode, clear count.
                    716:         */
                    717:        if ((bp->b_flags & B_ERROR) || !id->id_multisize)
                    718:                sc->sc_multicnt = 0;
                    719:        else {
                    720:                sc->sc_multicnt = id->id_multisize;
                    721:                printf("hd%d: max multiple size %u", unit, sc->sc_multicnt);
                    722:                /*
                    723:                 * Use 4096 since it is the minimum block size in FFS.
                    724:                 */
                    725:                if (sc->sc_multicnt > 4096 / 512)
                    726:                        sc->sc_multicnt = 4096 / 512;
                    727:                printf(", using %u\n", sc->sc_multicnt);
                    728:                sc->sc_flags |= HDF_SETMULTI;
                    729:        }
                    730:        brelse(bp);
                    731: }
                    732: 
                    733: /*
                    734:  * Write label to disk.
                    735:  */
                    736: int
                    737: hdwritelabel(dev)
                    738:        dev_t dev;
                    739: {
                    740:        int unit = hdunit(dev), error = 0;
                    741:        long labelsect;
                    742:        struct buf *bp;
                    743:        struct disklabel *lp = &hdlabel[unit];
                    744: 
                    745:        printf("hdwritelabel: no longer implemented\n");
                    746: 
                    747: #if 0
                    748:        bp = geteblk(lp->d_secsize);
                    749:        bp->b_flags = B_READ | B_ABS;
                    750:        bp->b_blkno = LBLLOC + lp->d_partitions[PART_DISK].p_offset;
                    751:        bp->b_bcount = lp->d_secsize;
                    752:        bp->b_dev = dev;
                    753:        hdstrategy(bp);
                    754:        biowait(bp);
                    755:        if (bp->b_flags & B_ERROR) {
                    756:                printf("hd%d: hdwritelabel(), error reading disklabel\n",unit);
                    757:                error = EIO;
                    758:                goto out;
                    759:        }
                    760:        *(struct disklabel *)bp->b_un.b_addr = *lp;  /* copy disk label */
                    761:        bp->b_flags = B_WRITE | B_ABS;
                    762:        hdstrategy(bp);
                    763:        biowait(bp);
                    764:        if (bp->b_flags & B_ERROR) {
                    765:                printf("hd%d: hdwritelabel(), error writing disklabel\n",unit);
                    766:                error = EIO;
                    767:        }
                    768:  out:
                    769:        brelse(bp);
                    770: #endif 0
                    771: 
                    772:        return (error);
                    773: }
                    774: 
                    775: /*
                    776:  * Strategy routine.
                    777:  * Enqueue request on drive.
                    778:  */
                    779: int
                    780: hdstrategy(bp)
                    781:        struct buf *bp;
                    782: {
                    783:        int unit = hdunit(bp->b_dev), part = hdpart(bp->b_dev), s;
                    784:        long bn, sz, maxsz;
                    785:        struct buf *dp;
                    786:        struct hdsoftc *sc = &hdsoftc[unit];
                    787:        struct bus_device *ui = hddinfo[unit];
                    788:        struct disklabel *lp = &hdlabel[unit];
                    789:        struct diskpart *label;
                    790: 
                    791:        if (bp->b_flags & B_IDENTIFY) {
                    792:                bp->b_cylin = 0;
                    793:                goto q;
                    794:        }
                    795:        bn = bp->b_blkno;
                    796:        if (bp->b_flags & B_ABS)
                    797:                goto q1;
                    798:        sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize;
                    799:        label=lookup_part(&array[MAX_IDE_PARTS*unit], hdpart(bp->b_dev));
                    800:        if (label) {
                    801:                maxsz = label->size;
                    802:        } else {
                    803:                bp->b_flags |= B_ERROR;
                    804:                bp->b_error = EINVAL;
                    805:                goto done;
                    806:        }
                    807: 
                    808:        if (bn < 0 || bn + sz > maxsz) {
                    809:                if (bn == maxsz) {
                    810:                        bp->b_resid = bp->b_bcount;
                    811:                        goto done;
                    812:                }
                    813:                sz = maxsz - bn;
                    814:                if (sz <= 0) {
                    815:                        bp->b_flags |= B_ERROR;
                    816:                        bp->b_error = EINVAL;
                    817:                        goto done;
                    818:                }
                    819:                bp->b_bcount = sz * lp->d_secsize;
                    820:        }
                    821:        bn += lp->d_partitions[part].p_offset;
                    822:        bn += label->start;
                    823: 
                    824:  q1:
                    825:        bp->b_cylin = (sc->sc_flags & HDF_LBA) ? bn : bn / lp->d_secpercyl;
                    826:  q:
                    827:        dp = &hdutab[unit];
                    828:        s = splbio();
                    829:        disksort(dp, bp);
                    830:        if (!dp->b_active) {
                    831:                hdustart(ui);
                    832:                if (!hdtab[ui->mi->unit].b_active)
                    833:                        hdstart(ui->mi);
                    834:        }
                    835:        splx(s);
                    836:        return(0);
                    837:  done:
                    838:        biodone(bp);
                    839:        return(0);
                    840: }
                    841: 
                    842: /*
                    843:  * Unit start routine.
                    844:  * Move request from drive to controller queue.
                    845:  */
                    846: int
                    847: hdustart(ui)
                    848:        struct bus_device *ui;
                    849: {
                    850:        struct buf *bp;
                    851:        struct buf *dp;
                    852: 
                    853:        bp = &hdutab[ui->unit];
                    854:        if (bp->b_actf == 0)
                    855:                return(0);
                    856:        dp = &hdtab[ui->mi->unit];
                    857:        if (dp->b_actf == 0)
                    858:                dp->b_actf = bp;
                    859:        else
                    860:                dp->b_actl->b_forw = bp;
                    861:        bp->b_forw = 0;
                    862:        dp->b_actl = bp;
                    863:        bp->b_active++;
                    864: }
                    865: 
                    866: /*
                    867:  * Start output on controller.
                    868:  */
                    869: int
                    870: hdstart(um)
                    871:        struct bus_ctlr *um;
                    872: {
                    873:        long bn;
                    874:        struct buf *bp;
                    875:        struct buf *dp;
                    876:        struct hdsoftc *sc;
                    877:        struct hdcsoftc *hdc;
                    878:        struct bus_device *ui;
                    879:        struct disklabel *lp;
                    880:        struct diskpart *label;
                    881: 
                    882:        /*
                    883:         * Pull a request from the controller queue.
                    884:         */
                    885:        dp = &hdtab[um->unit];
                    886:        if ((bp = dp->b_actf) == 0)
                    887:                return(0);
                    888:        bp = bp->b_actf;
                    889: 
                    890:        hdc = &hdcsoftc[um->unit];
                    891:        ui = hddinfo[hdunit(bp->b_dev)];
                    892:        sc = &hdsoftc[ui->unit];
                    893:        lp = &hdlabel[ui->unit];
                    894: 
                    895:        label = lookup_part(&array[MAX_IDE_PARTS*hdunit(bp->b_dev)], hdpart(bp->b_dev));
                    896: 
                    897:        /*
                    898:         * Mark controller busy.
                    899:         */
                    900:        dp->b_active++;
                    901: 
                    902:        if (bp->b_flags & B_IDENTIFY) {
                    903:                hdc->sc_state = IDENTIFY;
                    904:                goto doit;
                    905:        }
                    906: 
                    907:        /*
                    908:         * Figure out where this request is going.
                    909:         */
                    910:        if (sc->sc_flags & HDF_LBA)
                    911:                hdc->sc_cn = bp->b_cylin;
                    912:        else {
                    913:                bn = bp->b_blkno;
                    914:                if ((bp->b_flags & B_ABS) == 0) {
                    915:                        bn += label->start; /* partition must be valid */
                    916:                }
                    917:                hdc->sc_cn = bp->b_cylin;
                    918:                hdc->sc_sn = bn % lp->d_secpercyl;
                    919:                hdc->sc_tn = hdc->sc_sn / lp->d_nsectors;
                    920:                hdc->sc_sn %= lp->d_nsectors;
                    921:        }
                    922: 
                    923:        /*
                    924:         * Set up for multi-sector transfer.
                    925:         */
                    926:        hdc->sc_addr = bp->b_un.b_addr;
                    927:        hdc->sc_resid = bp->b_bcount;
                    928:        hdc->sc_wticks = 0;
                    929:        hdc->sc_recalerr = 0;
                    930:        hdc->sc_ioerr = 0;
                    931: 
                    932:        /*
                    933:         * Set initial transfer state.
                    934:         */
                    935:        if (sc->sc_flags & HDF_SETPARAM)
                    936:                hdc->sc_state = SETPARAM;
                    937:        else if (sc->sc_flags & HDF_RESTORE)
                    938:                hdc->sc_state = RESTORE;
                    939:        else if (sc->sc_flags & HDF_SETMULTI)
                    940:                hdc->sc_state = SETMULTI;
                    941:        else
                    942:                hdc->sc_state = TRANSFER;
                    943: 
                    944:  doit:
                    945:        /*
                    946:         * Call transfer state routine to do the actual I/O.
                    947:         */
                    948:        hdstate(um);
                    949: }
                    950: 
                    951: /*
                    952:  * Interrupt routine.
                    953:  */
                    954: int
                    955: hdintr(ctlr)
                    956:        int ctlr;
                    957: {
                    958:        int timedout;
                    959:        struct bus_ctlr *um = hdminfo[ctlr];
                    960:        struct bus_device *ui;
                    961:        struct buf *bp;
                    962:        struct buf *dp = &hdtab[ctlr];
                    963:        struct hdcsoftc *hdc = &hdcsoftc[ctlr];
                    964: 
                    965:        if (!dp->b_active) {
                    966:                (void) inb(HD_STATUS(um->address));
                    967:                printf("hdc%d: stray interrupt\n", ctlr);
                    968:                return(0);
                    969:        }
                    970:        timedout = hdc->sc_wticks >= OP_TIMEOUT;
                    971:        hdc->sc_wticks = 0;
                    972: 
                    973:        /*
                    974:         * Operation timed out, terminate request.
                    975:         */
                    976:        if (timedout) {
                    977:                bp = dp->b_actf->b_actf;
                    978:                ui = hddinfo[hdunit(bp->b_dev)];
                    979:                hderror("timed out", ui);
                    980:                hdsoftc[ui->unit].sc_flags |= HDF_RESTORE;
                    981:                bp->b_flags |= B_ERROR;
                    982:                bp->b_error = EIO;
                    983:                hddone(ui, bp);
                    984:                return(0);
                    985:        }
                    986: 
                    987:        /*
                    988:         * Let transfer state routine handle the rest.
                    989:         */
                    990:        hdstate(um);
                    991: }
                    992: 
                    993: /*
                    994:  * Transfer finite state machine driver.
                    995:  */
                    996: int
                    997: hdstate(um)
                    998:        struct bus_ctlr *um;
                    999: {
                   1000:        char *msg;
                   1001:        int op;
                   1002:        struct buf *bp;
                   1003:        struct hdsoftc *sc;
                   1004:        struct bus_device *ui;
                   1005:        struct disklabel *lp;
                   1006:        struct hdcsoftc *hdc = &hdcsoftc[um->unit];
                   1007:        struct hdbios *bg;
                   1008: 
                   1009:        bp = hdtab[um->unit].b_actf->b_actf;
                   1010:        ui = hddinfo[hdunit(bp->b_dev)];
                   1011:        lp = &hdlabel[ui->unit];
                   1012:        sc = &hdsoftc[ui->unit];
                   1013:        bg = &hdbios[ui->unit];
                   1014: 
                   1015:        /*
                   1016:         * Ensure controller is not busy.
                   1017:         */
                   1018:        if (!hdwait(um))
                   1019:                goto ctlr_err;
                   1020: 
                   1021:        while (1) switch (hdc->sc_state) {
                   1022: 
                   1023:        case SETPARAM:
                   1024:                /*
                   1025:                 * Set drive parameters.
                   1026:                 */
                   1027:                outb(HD_DRVHD(um->address),
                   1028:                     0xa0 | (ui->slave << 4) | (lp->d_ntracks - 1));
                   1029:                outb(HD_SECTCNT(um->address), lp->d_nsectors);
                   1030:                outb(HD_CMD(um->address), CMD_SETPARAM);
                   1031:                hdc->sc_state = SETPARAMDONE;
                   1032:                return(0);
                   1033: 
                   1034:        case SETPARAMDONE:
                   1035:                /*
                   1036:                 * Set parameters complete.
                   1037:                 */
                   1038:                if (msg = hderrchk(um))
                   1039:                        goto bad;
                   1040:                sc->sc_flags &= ~HDF_SETPARAM;
                   1041:                hdc->sc_state = RESTORE;
                   1042:                break;
                   1043: 
                   1044:        case RESTORE:
                   1045:                /*
                   1046:                 * Recalibrate drive.
                   1047:                 */
                   1048:                outb(HD_DRVHD(um->address), 0xa0 | (ui->slave << 4));
                   1049:                outb(HD_CMD(um->address), CMD_RESTORE);
                   1050:                hdc->sc_state = RESTOREDONE;
                   1051:                return(0);
                   1052: 
                   1053:        case RESTOREDONE:
                   1054:                /*
                   1055:                 * Recalibration complete.
                   1056:                 */
                   1057:                if (msg = hderrchk(um)) {
                   1058:                        if (++hdc->sc_recalerr == 2)
                   1059:                                goto bad;
                   1060:                        hdc->sc_state = RESTORE;
                   1061:                        break;
                   1062:                }
                   1063:                sc->sc_flags &= ~HDF_RESTORE;
                   1064:                hdc->sc_recalerr = 0;
                   1065:                if (sc->sc_flags & HDF_SETMULTI)
                   1066:                        hdc->sc_state = SETMULTI;
                   1067:                else
                   1068:                        hdc->sc_state = TRANSFER;
                   1069:                break;
                   1070: 
                   1071:        case TRANSFER:
                   1072:                /*
                   1073:                 * Perform I/O transfer.
                   1074:                 */
                   1075:                sc->sc_flags &= ~HDF_UNALIGNED;
                   1076:                hdc->sc_state = TRANSFERDONE;
                   1077:                hdc->sc_amt = hdc->sc_resid / lp->d_secsize;
                   1078:                if (hdc->sc_amt == 0) {
                   1079:                        sc->sc_flags |= HDF_UNALIGNED;
                   1080:                        hdc->sc_amt = 1;
                   1081:                } else if (hdc->sc_amt > 256)
                   1082:                        hdc->sc_amt = 256;
                   1083:                if (sc->sc_multicnt > 1 && hdc->sc_amt >= sc->sc_multicnt) {
                   1084:                        hdc->sc_cnt = sc->sc_multicnt;
                   1085:                        hdc->sc_amt -= hdc->sc_amt % hdc->sc_cnt;
                   1086:                        if (bp->b_flags & B_READ)
                   1087:                                op = CMD_READMULTI;
                   1088:                        else
                   1089:                                op = CMD_WRITEMULTI;
                   1090:                } else {
                   1091:                        hdc->sc_cnt = 1;
                   1092:                        if (bp->b_flags & B_READ)
                   1093:                                op = CMD_READ;
                   1094:                        else
                   1095:                                op = CMD_WRITE;
                   1096:                }
                   1097:                if (sc->sc_flags & HDF_LBA) {
                   1098:                        outb(HD_DRVHD(um->address),
                   1099:                             (0xe0 | (ui->slave << 4)
                   1100:                              | ((hdc->sc_cn >> 24) & 0x0f)));
                   1101:                        outb(HD_SECT(um->address), hdc->sc_cn);
                   1102:                        outb(HD_CYLLO(um->address), hdc->sc_cn >> 8);
                   1103:                        outb(HD_CYLHI(um->address), hdc->sc_cn >> 16);
                   1104:                } else {
                   1105:                        outb(HD_DRVHD(um->address),
                   1106:                             0xa0 | (ui->slave << 4) | hdc->sc_tn);
                   1107:                        outb(HD_SECT(um->address), hdc->sc_sn + 1);
                   1108:                        outb(HD_CYLLO(um->address), hdc->sc_cn);
                   1109:                        outb(HD_CYLHI(um->address), hdc->sc_cn >> 8);
                   1110:                }
                   1111:                outb(HD_SECTCNT(um->address), hdc->sc_amt & 0xff);
                   1112:                outb(HD_PRECOMP(um->address), bg->bg_precomp / 4);
                   1113:                outb(HD_CMD(um->address), op);
                   1114:                if ((bp->b_flags & B_READ) == 0) {
                   1115:                        int i;
                   1116:                        caddr_t buf;
                   1117: 
                   1118:                        if (sc->sc_flags & HDF_UNALIGNED) {
                   1119:                                buf = hdc->sc_buf;
                   1120:                                bcopy(hdc->sc_addr, buf, hdc->sc_resid);
                   1121:                                bzero(buf + hdc->sc_resid,
                   1122:                                      lp->d_secsize - hdc->sc_resid);
                   1123:                        } else
                   1124:                                buf = hdc->sc_addr;
                   1125:                        for (i = 0; i < 1000000; i++)
                   1126:                                if (inb(HD_STATUS(um->address)) & ST_DREQ) {
                   1127:                                        loutw(HD_DATA(um->address), buf,
                   1128:                                              hdc->sc_cnt * lp->d_secsize / 2);
                   1129:                                        return(0);
                   1130:                                }
                   1131:                        goto ctlr_err;
                   1132:                }
                   1133:                return(0);
                   1134: 
                   1135:        case TRANSFERDONE:
                   1136:                /*
                   1137:                 * Transfer complete.
                   1138:                 */
                   1139:                if (msg = hderrchk(um)) {
                   1140:                        if (++hdc->sc_ioerr == MAX_RETRIES)
                   1141:                                goto bad;
                   1142:                        /*
                   1143:                         * Every fourth attempt print a message
                   1144:                         * and recalibrate the drive.
                   1145:                         */
                   1146:                        if (hdc->sc_ioerr & 3)
                   1147:                                hdc->sc_state = TRANSFER;
                   1148:                        else {
                   1149:                                hderror(msg, ui);
                   1150:                                hdc->sc_state = RESTORE;
                   1151:                        }
                   1152:                        break;
                   1153:                }
                   1154:                if (bp->b_flags & B_READ) {
                   1155:                        if (sc->sc_flags & HDF_UNALIGNED) {
                   1156:                                linw(HD_DATA(um->address), hdc->sc_buf,
                   1157:                                     lp->d_secsize / 2);
                   1158:                                bcopy(hdc->sc_buf, hdc->sc_addr,
                   1159:                                      hdc->sc_resid);
                   1160:                        } else
                   1161:                                linw(HD_DATA(um->address), hdc->sc_addr,
                   1162:                                     hdc->sc_cnt * lp->d_secsize / 2);
                   1163:                }
                   1164:                hdc->sc_resid -= hdc->sc_cnt * lp->d_secsize;
                   1165:                if (hdc->sc_resid <= 0) {
                   1166:                        bp->b_resid = 0;
                   1167:                        hddone(ui, bp);
                   1168:                        return(0);
                   1169:                }
                   1170:                if (sc->sc_flags & HDF_LBA)
                   1171:                        hdc->sc_cn += hdc->sc_cnt;
                   1172:                else {
                   1173:                        hdc->sc_sn += hdc->sc_cnt;
                   1174:                        while (hdc->sc_sn >= lp->d_nsectors) {
                   1175:                                hdc->sc_sn -= lp->d_nsectors;
                   1176:                                if (++hdc->sc_tn == lp->d_ntracks) {
                   1177:                                        hdc->sc_tn = 0;
                   1178:                                        hdc->sc_cn++;
                   1179:                                }
                   1180:                        }
                   1181:                }
                   1182:                hdc->sc_ioerr = 0;
                   1183:                hdc->sc_addr += hdc->sc_cnt * lp->d_secsize;
                   1184:                hdc->sc_amt -= hdc->sc_cnt;
                   1185:                if (hdc->sc_amt == 0) {
                   1186:                        hdc->sc_state = TRANSFER;
                   1187:                        break;
                   1188:                }
                   1189:                if ((bp->b_flags & B_READ) == 0) {
                   1190:                        int i;
                   1191: 
                   1192:                        for (i = 0; i < 1000000; i++)
                   1193:                                if (inb(HD_STATUS(um->address)) & ST_DREQ) {
                   1194:                                        loutw(HD_DATA(um->address),
                   1195:                                              hdc->sc_addr,
                   1196:                                              hdc->sc_cnt * lp->d_secsize / 2);
                   1197:                                        return(0);
                   1198:                                }
                   1199:                        goto ctlr_err;
                   1200:                }
                   1201:                return(0);
                   1202: 
                   1203:        case IDENTIFY:
                   1204:                /*
                   1205:                 * Get drive info.
                   1206:                 */
                   1207:                hdc->sc_state = IDENTIFYDONE;
                   1208:                outb(HD_DRVHD(um->address), 0xa0 | (ui->slave << 4));
                   1209:                outb(HD_CMD(um->address), CMD_IDENTIFY);
                   1210:                return(0);
                   1211: 
                   1212:        case IDENTIFYDONE:
                   1213:                /*
                   1214:                 * Get drive info complete.
                   1215:                 */
                   1216:                if (msg = hderrchk(um))
                   1217:                        goto bad;
                   1218:                linw(HD_DATA(um->address), (u_short *)bp->b_un.b_addr, 256);
                   1219:                hddone(ui, bp);
                   1220:                return(0);
                   1221: 
                   1222:        case SETMULTI:
                   1223:                /*
                   1224:                 * Set multiple mode count.
                   1225:                 */
                   1226:                hdc->sc_state = SETMULTIDONE;
                   1227:                outb(HD_DRVHD(um->address), 0xa0 | (ui->slave << 4));
                   1228:                outb(HD_SECTCNT(um->address), sc->sc_multicnt);
                   1229:                outb(HD_CMD(um->address), CMD_SETMULTI);
                   1230:                return(0);
                   1231: 
                   1232:        case SETMULTIDONE:
                   1233:                /*
                   1234:                 * Set multiple mode count complete.
                   1235:                 */
                   1236:                sc->sc_flags &= ~HDF_SETMULTI;
                   1237:                if (msg = hderrchk(um)) {
                   1238:                        sc->sc_multicnt = 0;
                   1239:                        goto bad;
                   1240:                }
                   1241:                hdc->sc_state = TRANSFER;
                   1242:                break;
                   1243: 
                   1244:        default:
                   1245:                printf("hd%d: invalid state\n", ui->unit);
                   1246:                panic("hdstate");
                   1247:                /*NOTREACHED*/
                   1248:        }
                   1249: 
                   1250:  ctlr_err:
                   1251:        msg = "controller error";
                   1252: 
                   1253:  bad:
                   1254:        hderror(msg, ui);
                   1255:        bp->b_flags |= B_ERROR;
                   1256:        bp->b_error = EIO;
                   1257:        sc->sc_flags |= HDF_RESTORE;
                   1258:        hddone(ui, bp);
                   1259: }
                   1260: 
                   1261: /*
                   1262:  * Terminate current request and start
                   1263:  * any others that are queued.
                   1264:  */
                   1265: int
                   1266: hddone(ui, bp)
                   1267:        struct bus_device *ui;
                   1268:        struct buf *bp;
                   1269: {
                   1270:        struct bus_ctlr *um = ui->mi;
                   1271:        struct hdsoftc *sc = &hdsoftc[ui->unit];
                   1272:        struct hdcsoftc *hdc = &hdcsoftc[um->unit];
                   1273:        struct buf *dp = &hdtab[um->unit];
                   1274: 
                   1275:        sc->sc_flags &= ~HDF_UNALIGNED;
                   1276: 
                   1277:        /*
                   1278:         * Remove this request from queue.
                   1279:         */
                   1280:        hdutab[ui->unit].b_actf = bp->b_actf;
                   1281:        biodone(bp);
                   1282:        bp = &hdutab[ui->unit];
                   1283:        dp->b_actf = bp->b_forw;
                   1284: 
                   1285:        /*
                   1286:         * Mark controller and drive idle.
                   1287:         */
                   1288:        dp->b_active = 0;
                   1289:        bp->b_active = 0;
                   1290:        hdc->sc_state = IDLE;
                   1291: 
                   1292:        /*
                   1293:         * Start up other requests.
                   1294:         */
                   1295:        hdustart(ui);
                   1296:        hdstart(um);
                   1297: 
                   1298:        /*
                   1299:         * Wakeup anyone waiting for drive.
                   1300:         */
                   1301:        if (sc->sc_flags & HDF_WANT) {
                   1302:                sc->sc_flags &= ~HDF_WANT;
                   1303:                wakeup((caddr_t)sc);
                   1304:        }
                   1305: }
                   1306: 
                   1307: /*
                   1308:  * Wait for controller to be idle.
                   1309:  */
                   1310: int
                   1311: hdwait(um)
                   1312:        struct bus_ctlr *um;
                   1313: {
                   1314:        int i, status;
                   1315: 
                   1316:        for (i = 0; i < 1000000; i++) {
                   1317:                status = inb(HD_STATUS(um->address));
                   1318:                if ((status & ST_BUSY) == 0 && (status & ST_READY))
                   1319:                        return (status);
                   1320:        }
                   1321:        return (0);
                   1322: }
                   1323: 
                   1324: /*
                   1325:  * Check for errors on completion of an operation.
                   1326:  */
                   1327: char *
                   1328: hderrchk(um)
                   1329:        struct bus_ctlr *um;
                   1330: {
                   1331:        int status;
                   1332: 
                   1333:        status = inb(HD_STATUS(um->address));
                   1334:        if (status & ST_WRTFLT)
                   1335:                return ("write fault");
                   1336:        if (status & ST_ERROR) {
                   1337:                status = inb(HD_ERROR(um->address));
                   1338:                if (status & ERR_DAM)
                   1339:                        return ("data address mark not found");
                   1340:                if (status & ERR_TR0)
                   1341:                        return ("track 0 not found");
                   1342:                if (status & ERR_ID)
                   1343:                        return ("sector not found");
                   1344:                if (status & ERR_ECC)
                   1345:                        return ("uncorrectable ECC error");
                   1346:                if (status & ERR_BADBLK)
                   1347:                        return ("bad block detected");
                   1348:                if (status & ERR_ABORT)
                   1349:                        return ("command aborted");
                   1350:                return ("hard error");
                   1351:        }
                   1352:        return (NULL);
                   1353: }
                   1354: 
                   1355: /*
                   1356:  * Print an error message.
                   1357:  */
                   1358: hderror(msg, ui)
                   1359:        char *msg;
                   1360:        struct bus_device *ui;
                   1361: {
                   1362:        char *op;
                   1363:        int prn_sn = 0;
                   1364:        struct hdcsoftc *hdc = &hdcsoftc[ui->mi->unit];
                   1365: 
                   1366:        switch (hdc->sc_state) {
                   1367: 
                   1368:        case SETPARAM:
                   1369:        case SETPARAMDONE:
                   1370:                op = "SETPARAM: ";
                   1371:                break;
                   1372: 
                   1373:        case RESTORE:
                   1374:        case RESTOREDONE:
                   1375:                op = "RESTORE: ";
                   1376:                break;
                   1377: 
                   1378:        case TRANSFER:
                   1379:        case TRANSFERDONE:
                   1380:                if (hdutab[ui->unit].b_actf->b_flags & B_READ)
                   1381:                        op = "READ: ";
                   1382:                else
                   1383:                        op = "WRITE: ";
                   1384:                prn_sn = 1;
                   1385:                break;
                   1386: 
                   1387:        case IDENTIFY:
                   1388:        case IDENTIFYDONE:
                   1389:                op = "IDENTIFY: ";
                   1390:                break;
                   1391: 
                   1392:        case SETMULTI:
                   1393:        case SETMULTIDONE:
                   1394:                op = "SETMULTI: ";
                   1395:                break;
                   1396: 
                   1397:        default:
                   1398:                op = "";
                   1399:                break;
                   1400:        }
                   1401:        printf("hd%d: %s%s", ui->unit, op, msg);
                   1402:        if (prn_sn) {
                   1403:                if (hdsoftc[ui->unit].sc_flags & HDF_LBA)
                   1404:                        printf(", bn %d", hdc->sc_cn);
                   1405:                else
                   1406:                        printf(", cn %d tn %d sn %d",
                   1407:                               hdc->sc_cn, hdc->sc_tn, hdc->sc_sn + 1);
                   1408:        }
                   1409:        printf("\n");
                   1410: }
                   1411: 
                   1412: /*
                   1413:  * Watchdog routine.
                   1414:  * Check for any hung operations.
                   1415:  */
                   1416: void
                   1417: hdwatch()
                   1418: {
                   1419:        int unit, s;
                   1420: 
                   1421:        timeout(hdwatch, 0, hz);
                   1422:        s = splbio();
                   1423:        for (unit = 0; unit < NHDC; unit++)
                   1424:                if (hdtab[unit].b_active
                   1425:                    && ++hdcsoftc[unit].sc_wticks >= OP_TIMEOUT)
                   1426:                        hdintr(unit);
                   1427:        splx(s);
                   1428: }
                   1429: 
                   1430: #endif /* NHD > 0 && !LINUX_DEV */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.