📄 wd.c
字号:
/* $OpenBSD: wd.c,v 1.12 2000/04/10 07:06:16 csapuntz Exp $ *//* $NetBSD: wd.c,v 1.193 1999/02/28 17:15:27 explorer Exp $ *//* * Copyright (c) 1998 Manuel Bouyer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Manuel Bouyer. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *//*- * Copyright (c) 1998 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Charles M. Hannum and by Onno van der Linden. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */#if 0#include "rnd.h"#endif#include <sys/param.h>#include <sys/systm.h>#include <sys/kernel.h>#include <sys/conf.h>#include <sys/file.h>#include <sys/stat.h>#include <sys/ioctl.h>#include <sys/buf.h>#include <sys/uio.h>#include <sys/malloc.h>#include <sys/device.h>#include <sys/disklabel.h>#include <sys/disk.h>#include <sys/syslog.h>#include <sys/proc.h>#if NRND > 0#include <sys/rnd.h>#endif#include <sys/vnode.h>#include <vm/vm.h>#include <machine/intr.h>#include <machine/bus.h>#include <dev/ata/atareg.h>#include <dev/ata/atavar.h>#include <dev/ata/wdvar.h>#include <dev/ic/wdcreg.h>#include <sys/ataio.h>#if 0#include "locators.h"#endif#define WAITTIME (4 * hz) /* time to wait for a completion */#define WDIORETRIES_SINGLE 4 /* number of retries before single-sector */#define WDIORETRIES 5 /* number of retries before giving up */#define RECOVERYTIME hz/2 /* time to wait before retrying a cmd */#define WDUNIT(dev) DISKUNIT(dev)#ifndef PMON#define WDPART(dev) DISKPART(dev)#else#define WDPART(dev) RAW_PART#endif#define WDMINOR(unit, part) DISKMINOR(unit, part)#define MAKEWDDEV(maj, unit, part) MAKEDISKDEV(maj, unit, part)#define WDLABELDEV(dev) (MAKEWDDEV(major(dev), WDUNIT(dev), RAW_PART))#define DEBUG_INTR 0x01#define DEBUG_XFERS 0x02#define DEBUG_STATUS 0x04#define DEBUG_FUNCS 0x08#define DEBUG_PROBE 0x10#ifdef WDCDEBUGextern int wdcdebug_wd_mask; /* init'ed in ata_wdc.c */#define WDCDEBUG_PRINT(args, level) \ if (wdcdebug_wd_mask & (level)) \ printf args#else#define WDCDEBUG_PRINT(args, level)#endif#ifdef PMON#define device_unref(x)#define readdisklabel(x1, x2, x3, x4, x5) "no label"#endifstruct wd_softc { /* General disk infos */ struct device sc_dev; struct disk sc_dk; struct buf sc_q; /* IDE disk soft states */ struct ata_bio sc_wdc_bio; /* current transfer */ struct buf *sc_bp; /* buf being transfered */ struct ata_drive_datas *drvp; /* Our controller's infos */ int openings; struct ataparams sc_params;/* drive characteistics found */ int sc_flags; #define WDF_LOCKED 0x01#define WDF_WANTED 0x02#define WDF_WLABEL 0x04 /* label is writable */#define WDF_LABELLING 0x08 /* writing label *//* * XXX Nothing resets this yet, but disk change sensing will when ATA-4 is * more fully implemented. */#define WDF_LOADED 0x10 /* parameters loaded */#define WDF_WAIT 0x20 /* waiting for resources */#define WDF_LBA 0x40 /* using LBA mode */ int sc_capacity; int cyl; /* actual drive parameters */ int heads; int sectors; int retries; /* number of xfer retry */#if NRND > 0 rndsource_element_t rnd_source;#endif void *sc_sdhook;};#define sc_drive sc_wdc_bio.drive#define sc_mode sc_wdc_bio.mode#define sc_multi sc_wdc_bio.multi#define sc_badsect sc_wdc_bio.badsect#ifndef __OpenBSD__int wdprobe __P((struct device *, struct cfdata *, void *));#elseint wdprobe __P((struct device *, void *, void *));#endifvoid wdattach __P((struct device *, struct device *, void *));#ifndef PMONint wddetach __P((struct device *, int));int wdactivate __P((struct device *, enum devact));void wdzeroref __P((struct device *));#endifint wdprint __P((void *, char *));struct cfattach wd_ca = { sizeof(struct wd_softc), wdprobe, wdattach,#ifndef PMON wddetach, wdactivate, wdzeroref#endif};#ifdef __OpenBSD__struct cfdriver wd_cd = { NULL, "wd", DV_DISK};#elseextern struct cfdriver wd_cd;#endif/* * Glue necessary to hook WDCIOCCOMMAND into physio */struct wd_ioctl { LIST_ENTRY(wd_ioctl) wi_list; struct buf wi_bp; struct uio wi_uio; struct iovec wi_iov; atareq_t wi_atareq; struct wd_softc *wi_softc;};LIST_HEAD(, wd_ioctl) wi_head;struct wd_ioctl *wi_find __P((struct buf *));void wi_free __P((struct wd_ioctl *));struct wd_ioctl *wi_get __P((void));void wdioctlstrategy __P((struct buf *));void wdgetdefaultlabel __P((struct wd_softc *, struct disklabel *));void wdgetdisklabel __P((dev_t dev, struct wd_softc *, struct disklabel *, struct cpu_disklabel *, int));void wdstrategy __P((struct buf *));void wdstart __P((void *));void __wdstart __P((struct wd_softc*, struct buf *));void wdrestart __P((void*));int wd_get_params __P((struct wd_softc *, u_int8_t, struct ataparams *));void wd_flushcache __P((struct wd_softc *, int));void wd_shutdown __P((void*));struct dkdriver wddkdriver = { wdstrategy };/* XXX: these should go elsewhere */cdev_decl(wd);bdev_decl(wd);#ifdef DKBADvoid bad144intern __P((struct wd_softc *));#endif#ifndef PMON#define wdlock(wd) disk_lock(&(wd)->sc_dk)#define wdunlock(wd) disk_unlock(&(wd)->sc_dk)#else#define wdlock(wd) (0)#define wdunlock(wd)#endif#define wdlookup(unit) (struct wd_softc *)device_lookup(&wd_cd, (unit))intwdprobe(parent, match_, aux) struct device *parent;#ifndef __OpenBSD__ struct cfdata *match;#else void *match_;#endif void *aux;{ struct ata_atapi_attach *aa_link = aux; struct cfdata *match = match_; if (aa_link == NULL) return 0; if (aa_link->aa_type != T_ATA) return 0;#ifndef __OpenBSD__ if (match->cf_loc[ATACF_CHANNEL] != ATACF_CHANNEL_DEFAULT && match->cf_loc[ATACF_CHANNEL] != aa_link->aa_channel) return 0; if (match->cf_loc[ATACF_DRIVE] != ATACF_DRIVE_DEFAULT && match->cf_loc[ATACF_DRIVE] != aa_link->aa_drv_data->drive) return 0;#else if (match->cf_loc[0] != -1 && match->cf_loc[0] != aa_link->aa_channel) return 0; if (match->cf_loc[1] != -1 && match->cf_loc[1] != aa_link->aa_drv_data->drive) return 0;#endif return 1;}voidwdattach(parent, self, aux) struct device *parent, *self; void *aux;{ struct wd_softc *wd = (void *)self; struct ata_atapi_attach *aa_link= aux; int i, blank; char buf[41], c, *p, *q; WDCDEBUG_PRINT(("wdattach\n"), DEBUG_FUNCS | DEBUG_PROBE); wd->openings = aa_link->aa_openings; wd->drvp = aa_link->aa_drv_data; strncpy(wd->drvp->drive_name, wd->sc_dev.dv_xname, sizeof(wd->drvp->drive_name) - 1); wd->drvp->cf_flags = wd->sc_dev.dv_cfdata->cf_flags; /* read our drive info */ if (wd_get_params(wd, at_poll, &wd->sc_params) != 0) { printf("%s: IDENTIFY failed\n", wd->sc_dev.dv_xname); return; } for (blank = 0, p = wd->sc_params.atap_model, q = buf, i = 0; i < sizeof(wd->sc_params.atap_model); i++) { c = *p++; if (c == '\0') break; if (c != ' ') { if (blank) { *q++ = ' '; blank = 0; } *q++ = c; } else blank = 1; } *q++ = '\0'; printf(": <%s>\n", buf); wdc_probe_caps(wd->drvp, &wd->sc_params); wdc_print_caps(wd->drvp); if ((wd->sc_params.atap_multi & 0xff) > 1) { wd->sc_multi = wd->sc_params.atap_multi & 0xff; } else { wd->sc_multi = 1; } printf("%s: %d-sector PIO,", wd->sc_dev.dv_xname, wd->sc_multi); /* Prior to ATA-4, LBA was optional. */ if ((wd->sc_params.atap_capabilities1 & WDC_CAP_LBA) != 0) wd->sc_flags |= WDF_LBA;#if 0 /* ATA-4 requires LBA. */ if (wd->sc_params.atap_ataversion != 0xffff && wd->sc_params.atap_ataversion >= WDC_VER_ATA4) wd->sc_flags |= WDF_LBA;#endif if ((wd->sc_flags & WDF_LBA) != 0) { wd->sc_capacity = (wd->sc_params.atap_capacity[1] << 16) | wd->sc_params.atap_capacity[0]; printf(" LBA, %dMB, %d cyl, %d head, %d sec, %d sectors\n", wd->sc_capacity / (1048576 / DEV_BSIZE), wd->sc_params.atap_cylinders, wd->sc_params.atap_heads, wd->sc_params.atap_sectors, wd->sc_capacity); } else { wd->sc_capacity = wd->sc_params.atap_cylinders * wd->sc_params.atap_heads * wd->sc_params.atap_sectors; printf(" CHS, %dMB, %d cyl, %d head, %d sec, %d sectors\n", wd->sc_capacity / (1048576 / DEV_BSIZE), wd->sc_params.atap_cylinders, wd->sc_params.atap_heads, wd->sc_params.atap_sectors, wd->sc_capacity); } WDCDEBUG_PRINT(("%s: atap_dmatiming_mimi=%d, atap_dmatiming_recom=%d\n", self->dv_xname, wd->sc_params.atap_dmatiming_mimi, wd->sc_params.atap_dmatiming_recom), DEBUG_PROBE); /* * Initialize and attach the disk structure. */ wd->sc_dk.dk_driver = &wddkdriver; wd->sc_dk.dk_name = wd->sc_dev.dv_xname;#ifndef PMON disk_attach(&wd->sc_dk);#endif wd->sc_wdc_bio.lp = wd->sc_dk.dk_label; wd->sc_sdhook = shutdownhook_establish(wd_shutdown, wd); if (wd->sc_sdhook == NULL) printf("%s: WARNING: unable to establish shutdown hook\n", wd->sc_dev.dv_xname); #if NRND > 0 rnd_attach_source(&wd->rnd_source, wd->sc_dev.dv_xname, RND_TYPE_DISK, 0);#endif}#ifndef PMONintwdactivate(self, act) struct device *self; enum devact act;{ int rv = 0; switch (act) { case DVACT_ACTIVATE: break; case DVACT_DEACTIVATE: /* * Nothing to do; we key off the device's DVF_ACTIVATE. */ break; } return (rv);}intwddetach(self, flags) struct device *self; int flags;{ struct wd_softc *sc = (struct wd_softc *)self; struct buf *dp, *bp; int s, bmaj, cmaj, mn; /* Remove unprocessed buffers from queue */ s = splbio(); for (dp = &sc->sc_q; (bp = dp->b_actf) != NULL; ) { dp->b_actf = bp->b_actf; bp->b_error = ENXIO; bp->b_flags |= B_ERROR; biodone(bp); } splx(s); /* locate the major number */ mn = WDMINOR(self->dv_unit, 0); for (bmaj = 0; bmaj < nblkdev; bmaj++) if (bdevsw[bmaj].d_open == wdopen) vdevgone(bmaj, mn, mn + MAXPARTITIONS - 1, VBLK); for (cmaj = 0; cmaj < nchrdev; cmaj++) if (cdevsw[cmaj].d_open == wdopen) vdevgone(cmaj, mn, mn + MAXPARTITIONS - 1, VCHR); /* Get rid of the shutdown hook. */ if (sc->sc_sdhook != NULL) shutdownhook_disestablish(sc->sc_sdhook);#if NRND > 0 /* Unhook the entropy source. */ rnd_detach_source(&sc->rnd_source);#endif return (0);}voidwdzeroref(self) struct device *self;{ struct wd_softc *sc = (struct wd_softc *)self; /* Detach disk. */ disk_detach(&sc->sc_dk);}#endif /* PMON *//* * Read/write routine for a buffer. Validates the arguments and schedules the * transfer. Does not wait for the transfer to complete. */voidwdstrategy(bp) struct buf *bp;{ struct wd_softc *wd; int s; wd = wdlookup(WDUNIT(bp->b_dev)); if (wd == NULL) { bp->b_error = ENXIO; goto bad; } WDCDEBUG_PRINT(("wdstrategy (%s)\n", wd->sc_dev.dv_xname), DEBUG_XFERS); /* Valid request? */ if (bp->b_blkno < 0 || (bp->b_bcount % wd->sc_dk.dk_label->d_secsize) != 0 || (bp->b_bcount / wd->sc_dk.dk_label->d_secsize) >= (1 << NBBY)) { bp->b_error = EINVAL; goto bad; } /* If device invalidated (e.g. media change, door open), error. */ if ((wd->sc_flags & WDF_LOADED) == 0) { bp->b_error = EIO; goto bad; } /* If it's a null transfer, return immediately. */ if (bp->b_bcount == 0) goto done; /* * Do bounds checking, adjust transfer. if error, process. * If end of partition, just return. */#ifndef PMON if (WDPART(bp->b_dev) != RAW_PART && bounds_check_with_label(bp, wd->sc_dk.dk_label, wd->sc_dk.dk_cpulabel, (wd->sc_flags & (WDF_WLABEL|WDF_LABELLING)) != 0) <= 0) goto done;#endif /* Queue transfer on drive, activate drive and controller if idle. */ s = splbio(); disksort(&wd->sc_q, bp); wdstart(wd); splx(s); device_unref(&wd->sc_dev); return;bad: bp->b_flags |= B_ERROR;done: /* Toss transfer; we're done early. */ bp->b_resid = bp->b_bcount;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -