[BACK]Return to wdc.c CVS log [TXT][DIR] Up to [local] / sys / arch / jornada / stand / boot

Annotation of sys/arch/jornada/stand/boot/wdc.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: wdc.c,v 1.2 2006/07/29 15:01:49 kettenis Exp $        */
                      2: /*     $NetBSD: wdc.c,v 1.7 2005/12/11 12:17:06 christos Exp $ */
                      3:
                      4: /*-
                      5:  * Copyright (c) 2003 The NetBSD Foundation, Inc.
                      6:  * All rights reserved.
                      7:  *
                      8:  * This code is derived from software contributed to The NetBSD Foundation
                      9:  * by Manuel Bouyer.
                     10:  *
                     11:  * Redistribution and use in source and binary forms, with or without
                     12:  * modification, are permitted provided that the following conditions
                     13:  * are met:
                     14:  * 1. Redistributions of source code must retain the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer.
                     16:  * 2. Redistributions in binary form must reproduce the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer in the
                     18:  *    documentation and/or other materials provided with the distribution.
                     19:  * 3. All advertising materials mentioning features or use of this software
                     20:  *    must display the following acknowledgement:
                     21:  *        This product includes software developed by the NetBSD
                     22:  *        Foundation, Inc. and its contributors.
                     23:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     24:  *    contributors may be used to endorse or promote products derived
                     25:  *    from this software without specific prior written permission.
                     26:  *
                     27:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     28:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     29:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     30:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     31:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     32:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     33:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     34:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     35:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     36:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     37:  * POSSIBILITY OF SUCH DAMAGE.
                     38:  */
                     39:
                     40: #include <sys/types.h>
                     41: #include <machine/param.h>
                     42:
                     43: #include "libsa.h"
                     44: #include "wdvar.h"
                     45:
                     46: #define WDCDELAY       100
                     47: #define WDCNDELAY_RST  31000 * 10
                     48:
                     49: static int  wdcprobe(struct wdc_channel *chp);
                     50: static int  wdc_wait_for_ready(struct wdc_channel *chp);
                     51: static int  wdc_read_block(struct wd_softc *sc, struct wdc_command *wd_c);
                     52: static int  __wdcwait_reset(struct wdc_channel *chp, int drv_mask);
                     53:
                     54: /*
                     55:  * Reset the controller.
                     56:  */
                     57: static int
                     58: __wdcwait_reset(chp, drv_mask)
                     59:        struct wdc_channel *chp;
                     60:        int drv_mask;
                     61: {
                     62:        int timeout;
                     63:        u_int8_t st0, st1;
                     64:
                     65:        /* wait for BSY to deassert */
                     66:        for (timeout = 0; timeout < WDCNDELAY_RST; timeout++) {
                     67:                WDC_WRITE_REG(chp, wd_sdh, WDSD_IBM); /* master */
                     68:                delay(10);
                     69:                st0 = WDC_READ_REG(chp, wd_status);
                     70:                WDC_WRITE_REG(chp, wd_sdh, WDSD_IBM | 0x10); /* slave */
                     71:                delay(10);
                     72:                st1 = WDC_READ_REG(chp, wd_status);
                     73:
                     74:                if ((drv_mask & 0x01) == 0) {
                     75:                        /* no master */
                     76:                        if ((drv_mask & 0x02) != 0 && (st1 & WDCS_BSY) == 0) {
                     77:                                /* No master, slave is ready, it's done */
                     78:                                goto end;
                     79:                        }
                     80:                } else if ((drv_mask & 0x02) == 0) {
                     81:                        /* no slave */
                     82:                        if ((drv_mask & 0x01) != 0 && (st0 & WDCS_BSY) == 0) {
                     83:                                /* No slave, master is ready, it's done */
                     84:                                goto end;
                     85:                        }
                     86:                } else {
                     87:                        /* Wait for both master and slave to be ready */
                     88:                        if ((st0 & WDCS_BSY) == 0 && (st1 & WDCS_BSY) == 0) {
                     89:                                goto end;
                     90:                        }
                     91:                }
                     92:
                     93:                delay(WDCDELAY);
                     94:        }
                     95:
                     96:        /* Reset timed out. Maybe it's because drv_mask was not right */
                     97:        if (st0 & WDCS_BSY)
                     98:                drv_mask &= ~0x01;
                     99:        if (st1 & WDCS_BSY)
                    100:                drv_mask &= ~0x02;
                    101:
                    102: end:
                    103:        return (drv_mask);
                    104: }
                    105:
                    106: /* Test to see controller with at last one attached drive is there.
                    107:  * Returns a bit for each possible drive found (0x01 for drive 0,
                    108:  * 0x02 for drive 1).
                    109:  * Logic:
                    110:  * - If a status register is at 0xff, assume there is no drive here
                    111:  *   (ISA has pull-up resistors).  Similarly if the status register has
                    112:  *   the value we last wrote to the bus (for IDE interfaces without pullups).
                    113:  *   If no drive at all -> return.
                    114:  * - reset the controller, wait for it to complete (may take up to 31s !).
                    115:  *   If timeout -> return.
                    116:  */
                    117: static int
                    118: wdcprobe(chp)
                    119:        struct wdc_channel *chp;
                    120: {
                    121:        u_int8_t st0, st1, sc, sn, cl, ch;
                    122:        u_int8_t ret_value = 0x03;
                    123:        u_int8_t drive;
                    124:        int found;
                    125:
                    126:        /*
                    127:         * Sanity check to see if the wdc channel responds at all.
                    128:         */
                    129:        WDC_WRITE_REG(chp, wd_sdh, WDSD_IBM);
                    130:        delay(10);
                    131:        st0 = WDC_READ_REG(chp, wd_status);
                    132:        WDC_WRITE_REG(chp, wd_sdh, WDSD_IBM | 0x10);
                    133:        delay(10);
                    134:        st1 = WDC_READ_REG(chp, wd_status);
                    135:
                    136:        if (st0 == 0xff || st0 == WDSD_IBM)
                    137:                ret_value &= ~0x01;
                    138:        if (st1 == 0xff || st1 == (WDSD_IBM | 0x10))
                    139:                ret_value &= ~0x02;
                    140:        if (ret_value == 0)
                    141:                return (ENXIO);
                    142:
                    143:        /* assert SRST, wait for reset to complete */
                    144:        WDC_WRITE_REG(chp, wd_sdh, WDSD_IBM);
                    145:        delay(10);
                    146:        WDC_WRITE_CTLREG(chp, wd_aux_ctlr, WDCTL_RST | WDCTL_IDS);
                    147:        delay(1000);
                    148:        WDC_WRITE_CTLREG(chp, wd_aux_ctlr, WDCTL_IDS);
                    149:        delay(1000);
                    150:        (void) WDC_READ_REG(chp, wd_error);
                    151:        WDC_WRITE_CTLREG(chp, wd_aux_ctlr, WDCTL_4BIT);
                    152:        delay(10);
                    153:
                    154:        ret_value = __wdcwait_reset(chp, ret_value);
                    155:
                    156:        /* if reset failed, there's nothing here */
                    157:        if (ret_value == 0)
                    158:                return (ENXIO);
                    159:
                    160:        /*
                    161:         * Test presence of drives. First test register signatures looking for
                    162:         * ATAPI devices. If it's not an ATAPI and reset said there may be
                    163:         * something here assume it's ATA or OLD. Ghost will be killed later in
                    164:         * attach routine.
                    165:         */
                    166:        found = 0;
                    167:        for (drive = 0; drive < 2; drive++) {
                    168:                if ((ret_value & (0x01 << drive)) == 0)
                    169:                        continue;
                    170:                return (0);
                    171:        }
                    172:        return (ENXIO);
                    173: }
                    174:
                    175: /*
                    176:  * Initialize the device.
                    177:  */
                    178: int
                    179: wdc_init(sc, unit)
                    180:        struct wd_softc *sc;
                    181:        u_int unit;
                    182: {
                    183:        if (pciide_init(&sc->sc_channel, unit) != 0)
                    184:                return (ENXIO);
                    185:        if (wdcprobe(&sc->sc_channel) != 0)
                    186:                return (ENXIO);
                    187:        return (0);
                    188: }
                    189:
                    190: /*
                    191:  * Wait until the device is ready.
                    192:  */
                    193: int
                    194: wdc_wait_for_ready(chp)
                    195:        struct wdc_channel *chp;
                    196: {
                    197:        u_int timeout;
                    198:        for (timeout = WDC_TIMEOUT; timeout > 0; --timeout) {
                    199:                if ((WDC_READ_REG(chp, wd_status) & (WDCS_BSY | WDCS_DRDY))
                    200:                                == WDCS_DRDY)
                    201:                        return (0);
                    202:        }
                    203:        return (ENXIO);
                    204: }
                    205:
                    206: /*
                    207:  * Read one block off the device.
                    208:  */
                    209: int
                    210: wdc_read_block(sc, wd_c)
                    211:        struct wd_softc *sc;
                    212:        struct wdc_command *wd_c;
                    213: {
                    214:        int i;
                    215:        struct wdc_channel *chp = &sc->sc_channel;
                    216:        u_int16_t *ptr = (u_int16_t*)wd_c->data;
                    217:
                    218:        if (ptr == NULL)
                    219:                return (0);
                    220:
                    221:        for (i = wd_c->bcount; i > 0; i -= sizeof(u_int16_t))
                    222:                *ptr++ = WDC_READ_DATA(chp);
                    223:
                    224:        return (0);
                    225: }
                    226:
                    227: /*
                    228:  * Send a command to the device (CHS and LBA addressing).
                    229:  */
                    230: int
                    231: wdccommand(wd, wd_c)
                    232:        struct wd_softc *wd;
                    233:        struct wdc_command *wd_c;
                    234: {
                    235:        u_int8_t err;
                    236:        struct wdc_channel *chp = &wd->sc_channel;
                    237:
                    238: #if 0
                    239:        DPRINTF(("wdccommand(%d, %d, %d, %d, %d, %d, %d)\n",
                    240:            wd_c->drive, wd_c->r_command, wd_c->r_cyl,
                    241:            wd_c->r_head, wd_c->r_sector, wd_c->bcount,
                    242:            wd_c->r_precomp));
                    243: #endif
                    244:
                    245:        WDC_WRITE_REG(chp, wd_precomp, wd_c->r_precomp);
                    246:        WDC_WRITE_REG(chp, wd_seccnt, wd_c->r_count);
                    247:        WDC_WRITE_REG(chp, wd_sector, wd_c->r_sector);
                    248:        WDC_WRITE_REG(chp, wd_cyl_lo, wd_c->r_cyl);
                    249:        WDC_WRITE_REG(chp, wd_cyl_hi, wd_c->r_cyl >> 8);
                    250:        WDC_WRITE_REG(chp, wd_sdh,
                    251:            WDSD_IBM | (wd_c->drive << 4) | wd_c->r_head);
                    252:        WDC_WRITE_REG(chp, wd_command, wd_c->r_command);
                    253:
                    254:        if (wdc_wait_for_ready(chp) != 0)
                    255:                return (ENXIO);
                    256:
                    257:        if (WDC_READ_REG(chp, wd_status) & WDCS_ERR) {
                    258:                DPRINTF(("wd%d: error %x\n", wd->sc_unit,
                    259:                    WDC_READ_REG(chp, wd_error)));
                    260:                return (ENXIO);
                    261:        }
                    262:
                    263:        return (0);
                    264: }
                    265:
                    266: /*
                    267:  * Send a command to the device (LBA48 addressing).
                    268:  */
                    269: int
                    270: wdccommandext(wd, wd_c)
                    271:        struct wd_softc *wd;
                    272:        struct wdc_command *wd_c;
                    273: {
                    274:        u_int8_t err;
                    275:        struct wdc_channel *chp = &wd->sc_channel;
                    276:
                    277:        /* Select drive, head, and addressing mode. */
                    278:        WDC_WRITE_REG(chp, wd_sdh, (wd_c->drive << 4) | WDSD_LBA);
                    279:
                    280:        /* previous */
                    281:        WDC_WRITE_REG(chp, wd_features, 0);
                    282:        WDC_WRITE_REG(chp, wd_seccnt, wd_c->r_count >> 8);
                    283:        WDC_WRITE_REG(chp, wd_lba_hi, wd_c->r_blkno >> 40);
                    284:        WDC_WRITE_REG(chp, wd_lba_mi, wd_c->r_blkno >> 32);
                    285:        WDC_WRITE_REG(chp, wd_lba_lo, wd_c->r_blkno >> 24);
                    286:
                    287:        /* current */
                    288:        WDC_WRITE_REG(chp, wd_features, 0);
                    289:        WDC_WRITE_REG(chp, wd_seccnt, wd_c->r_count);
                    290:        WDC_WRITE_REG(chp, wd_lba_hi, wd_c->r_blkno >> 16);
                    291:        WDC_WRITE_REG(chp, wd_lba_mi, wd_c->r_blkno >> 8);
                    292:        WDC_WRITE_REG(chp, wd_lba_lo, wd_c->r_blkno);
                    293:
                    294:        /* Send command. */
                    295:        WDC_WRITE_REG(chp, wd_command, wd_c->r_command);
                    296:
                    297:        if (wdc_wait_for_ready(chp) != 0)
                    298:                return (ENXIO);
                    299:
                    300:        if (WDC_READ_REG(chp, wd_status) & WDCS_ERR) {
                    301:                DPRINTF(("wd%d: error %x\n", wd->sc_unit,
                    302:                    WDC_READ_REG(chp, wd_error)));
                    303:                return (ENXIO);
                    304:        }
                    305:
                    306:        return (0);
                    307: }
                    308:
                    309: /*
                    310:  * Issue 'device identify' command.
                    311:  */
                    312: int
                    313: wdc_exec_identify(wd, data)
                    314:        struct wd_softc *wd;
                    315:        void *data;
                    316: {
                    317:        int error;
                    318:        struct wdc_command wd_c;
                    319:
                    320:        memset(&wd_c, 0, sizeof(wd_c));
                    321:
                    322:        wd_c.drive = wd->sc_drive;
                    323:        wd_c.r_command = WDCC_IDENTIFY;
                    324:        wd_c.bcount = DEV_BSIZE;
                    325:        wd_c.data = data;
                    326:
                    327:        if ((error = wdccommand(wd, &wd_c)) != 0)
                    328:                return (error);
                    329:
                    330:        return wdc_read_block(wd, &wd_c);
                    331: }
                    332:
                    333: /*
                    334:  * Issue 'read' command.
                    335:  */
                    336: int
                    337: wdc_exec_read(wd, cmd, blkno, data)
                    338:        struct wd_softc *wd;
                    339:        u_int8_t cmd;
                    340:        daddr_t blkno;
                    341:        void *data;
                    342: {
                    343:        int error;
                    344:        struct wdc_command wd_c;
                    345:
                    346:        memset(&wd_c, 0, sizeof(wd_c));
                    347:
                    348:        if (wd->sc_flags & WDF_LBA48) {
                    349:                /* LBA48 */
                    350:                wd_c.r_blkno = blkno;
                    351:        } else if (wd->sc_flags & WDF_LBA) {
                    352:                /* LBA */
                    353:                wd_c.r_sector = (blkno >> 0) & 0xff;
                    354:                wd_c.r_cyl = (blkno >> 8) & 0xffff;
                    355:                wd_c.r_head = (blkno >> 24) & 0x0f;
                    356:                wd_c.r_head |= WDSD_LBA;
                    357:        } else {
                    358:                /* LHS */
                    359:                wd_c.r_sector = blkno % wd->sc_label.d_nsectors;
                    360:                wd_c.r_sector++;    /* Sectors begin with 1, not 0. */
                    361:                blkno /= wd->sc_label.d_nsectors;
                    362:                wd_c.r_head = blkno % wd->sc_label.d_ntracks;
                    363:                blkno /= wd->sc_label.d_ntracks;
                    364:                wd_c.r_cyl = blkno;
                    365:                wd_c.r_head |= WDSD_CHS;
                    366:        }
                    367:
                    368:        wd_c.data = data;
                    369:        wd_c.r_count = 1;
                    370:        wd_c.drive = wd->sc_drive;
                    371:        wd_c.r_command = cmd;
                    372:        wd_c.bcount = wd->sc_label.d_secsize;
                    373:
                    374:        if (wd->sc_flags & WDF_LBA48)
                    375:                error = wdccommandext(wd, &wd_c);
                    376:        else
                    377:                error = wdccommand(wd, &wd_c);
                    378:
                    379:        if (error != 0)
                    380:                return (error);
                    381:
                    382:        return wdc_read_block(wd, &wd_c);
                    383: }

CVSweb