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