📄 sd.c
字号:
/* * Copyright (c) 1990, 1992, 1993 * The Regents of the University of California. All rights reserved. * * This software was developed by the Computer Systems Engineering group * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and * contributed to Berkeley. * * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Lawrence Berkeley Laboratory. * * 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 University of * California, Berkeley and its contributors. * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. * * @(#)sd.c 8.1 (Berkeley) 6/10/93 * * from: $Header: sd.c,v 1.27 93/04/29 01:22:19 torek Exp $ *//* * SCSI CCS (Command Command Set) disk driver. * * MACHINE INDEPENDENT (do not put machine dependent goo in here!) * * (from sd.c,v 1.7 90/12/15 14:11:26 van Exp) */#include <sys/param.h>#include <sys/systm.h>#include <sys/proc.h>#include <sys/buf.h>#include <sys/errno.h>#include <sys/device.h>#include <sys/disklabel.h>#include <sys/dkstat.h>#include <sys/disk.h>#include <sys/ioctl.h>#include <sys/malloc.h>#include <dev/scsi/scsi.h>#include <dev/scsi/disk.h>#include <dev/scsi/scsivar.h>#include <dev/scsi/scsi_ioctl.h>#include <machine/cpu.h>#include <dev/scsi/sdtrace.h>#ifdef sparc /* XXX */#define SUN_LABEL_HACK /* XXX */#endif /* XXX */#ifdef SUN_LABEL_HACK#include <sparc/sunos/sun_disklabel.h>#endif/* * Per-disk variables. * * sd_dk contains all the `disk' specific stuff (label/partitions, * transfer rate, etc). We need only things that are special to * scsi disks. Note that our blocks are in terms of DEV_BSIZE blocks. */struct sd_softc { struct dkdevice sc_dk; /* base disk device, must be first */ struct unit sc_unit; /* scsi unit */ pid_t sc_format_pid; /* process using "format" mode */ u_char sc_type; /* drive type */ u_char sc_bshift; /* convert device blocks to DEV_BSIZE blks */ short sc_flags; /* see below */ u_int sc_blks; /* number of blocks on device */ int sc_blksize; /* device block size in bytes */ /* should be in dkdevice?? */ struct buf sc_tab; /* transfer queue */ /* statistics */ long sc_resets; /* number of times reset */ long sc_transfers; /* count of total transfers */ long sc_partials; /* count of `partial' transfers */ /* for user formatting */ struct scsi_cdb sc_cmd; struct scsi_fmt_sense sc_sense;};#define SDF_ALIVE 1 /* drive OK for regular kernel use *//* definition of the autoconfig driver */int sdmatch __P((struct device *, struct cfdata *, void *));void sdattach __P((struct device *, struct device *, void *));struct cfdriver sdcd = { NULL, "sd", sdmatch, sdattach, DV_DISK, sizeof(struct sd_softc) };/* definition of the unit driver, for hba */void sdigo __P((struct device *, struct scsi_cdb *));void sdgo __P((struct device *, struct scsi_cdb *));void sdintr __P((struct device *, int, int));void sdreset __P((struct unit *));static struct unitdriver sdunitdriver = { /*sdgo, sdintr*/ sdreset };/* definition of the disk driver, for kernel */void sdstrategy __P((struct buf *));static struct dkdriver sddkdriver = { sdstrategy };#ifdef DEBUGint sddebug = 1;#define SDB_ERROR 0x01#define SDB_PARTIAL 0x02#endif#define sdunit(x) (minor(x) >> 3)#define sdpart(x) (minor(x) & 0x7)#define b_cylin b_resid#define SDRETRY 2/* * Table of scsi commands users are allowed to access via `format' * mode. 0 means not legal. 1 means `immediate' (doesn't need dma). * -1 means needs dma and/or wait for intr (i.e., `slow'). */static char legal_cmds[256] = {/***** 0 1 2 3 4 5 6 7 8 9 A B C D E F *//*00*/ 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/*10*/ 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,/*20*/ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/*30*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/*60*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/*a0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,};intsdmatch(parent, cf, aux) struct device *parent; register struct cfdata *cf; void *aux;{ register struct scsi_attach_args *sa = aux;#ifdef DEBUG char *whynot;#endif /* * unit number must match, or be given as `any' */ if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != sa->sa_unit) return (0); /* * drive must be a disk, and of a kind we recognize */ if ((sa->sa_inq_status & STS_MASK) != STS_GOOD) {#ifdef DEBUG whynot = "INQUIRY failed";#endif goto notdisk; } switch (sa->sa_si.si_type & TYPE_TYPE_MASK) { case TYPE_DAD: /* disk */ case TYPE_WORM: /* WORM */ case TYPE_ROM: /* CD-ROM */ case TYPE_MO: /* Magneto-optical */ case TYPE_JUKEBOX: /* medium changer */ break; default: notdisk:#ifdef DEBUG whynot = "not a disk"; printf("[not matching `sd' at unit %d: %s]\n", sa->sa_unit, whynot);#endif return (0); } /* * It is a disk of some kind; take it. We will figure out * the rest in the attach routine. */ return (1);}/* * Attach a disk (called after sdmatch returns true). * Note that this routine is never reentered (so we can use statics). */voidsdattach(parent, self, aux) struct device *parent, *self; void *aux;{ register struct sd_softc *sc = (struct sd_softc *)self; register struct scsi_attach_args *sa = aux; register int i; char vendor[10], drive[17], rev[5]; static u_char capbuf[8]; static struct scsi_cdb cap = { CMD_READ_CAPACITY };#ifdef SUN_LABEL_HACK static struct scsi_cdb rd0 = { CMD_READ10, 0, 0, 0, 0, 0, 0, 0, 1, 0 }; caddr_t sector;#endif /* * Declare our existence. */ sc->sc_unit.u_driver = &sdunitdriver; scsi_establish(&sc->sc_unit, &sc->sc_dk.dk_dev, sa->sa_unit); /* * Figure out what kind of disk this is. * We only accepted it if the inquiry succeeded, so * we can inspect those fields. */ i = (sa->sa_si.si_version >> VER_ANSI_SHIFT) & VER_ANSI_MASK; if (i == 1 || i == 2) { scsi_inq_ansi((struct scsi_inq_ansi *)&sa->sa_si, vendor, drive, rev); printf(": %s %s", vendor, drive); /* XXX should we even ever bother printing this? */ if (rev[0]) printf(" %s", rev); } else { /* bleah */ bcopy("<unknown>", vendor, 10); bcopy("<unknown>", drive, 10); printf(": type 0x%x, qual 0x%x, ver %d", sa->sa_si.si_type, sa->sa_si.si_qual, sa->sa_si.si_version); } CDB10(&cap)->cdb_lun_rel = sc->sc_unit.u_unit << 5; i = (*sc->sc_unit.u_hbd->hd_icmd)(sc->sc_unit.u_hba, sc->sc_unit.u_targ, &cap, (char *)capbuf, sizeof capbuf, B_READ); i &= STS_MASK; if (i == STS_GOOD) {#define NUMBER(p) (((p)[0] << 24) | ((p)[1] << 16) | ((p)[2] << 8) | (p)[3]) sc->sc_blks = NUMBER(&capbuf[0]); sc->sc_blksize = NUMBER(&capbuf[4]); } else if (i == STS_CHECKCOND && (strcmp(vendor, "HP") == 0 && strcmp(drive, "S6300.650A") == 0)) { /* XXX unformatted or nonexistent MO medium: fake it */ sc->sc_blks = 318664; sc->sc_blksize = 1024; } else { /* XXX shouldn't bail for removable media */ printf(": unable to determine drive capacity [sts=%x]\n", i); return; } /* return value from read capacity is last valid block, not nblocks */ sc->sc_blks++; printf(", %u %d byte blocks\n", sc->sc_blks, sc->sc_blksize); if (sc->sc_blksize != DEV_BSIZE) { for (i = sc->sc_blksize; i > DEV_BSIZE; i >>= 1) ++sc->sc_bshift; if (i != DEV_BSIZE) { printf("%s: blksize not multiple of %d: cannot use\n", sc->sc_dk.dk_dev.dv_xname, DEV_BSIZE); return; } sc->sc_blks <<= sc->sc_bshift; } sc->sc_type = sa->sa_si.si_type; /* sufficient? */ sc->sc_dk.dk_driver = &sddkdriver;#ifdef notyet dk_establish(&sc->sc_dk); /* READ DISK LABEL HERE, UNLESS REMOVABLE MEDIUM... NEEDS THOUGHT */#else sc->sc_dk.dk_label.d_secsize = 512; /* XXX */ sc->sc_dk.dk_bps = (3600/60) * 32 * 512;/* XXX */#ifdef SUN_LABEL_HACK sector = (caddr_t)malloc(sc->sc_blksize, M_DEVBUF, M_NOWAIT); CDB10(&rd0)->cdb_lun_rel = sc->sc_unit.u_unit << 5; i = (*sc->sc_unit.u_hbd->hd_icmd)(sc->sc_unit.u_hba, sc->sc_unit.u_targ, &rd0, sector, sc->sc_blksize, B_READ); if (i == STS_GOOD) { printf("%s: <%s>\n", sc->sc_dk.dk_dev.dv_xname, ((struct sun_disklabel *)sector)->sl_text); if (sun_disklabel(sector, &sc->sc_dk.dk_label)) sc->sc_flags |= SDF_ALIVE; else printf("%s: sun_disklabel fails\n", sc->sc_dk.dk_dev.dv_xname); } else printf("%s: could not read sector 0 for disk label\n", sc->sc_dk.dk_dev.dv_xname); free(sector, M_DEVBUF);#endif#endif /* notyet */}/* * Reset a disk, after a SCSI bus reset. * * XXX untested and probably incomplete/incorrect */voidsdreset(u) register struct unit *u;{ register struct sd_softc *sc = (struct sd_softc *)u->u_dev; printf(" %s", sc->sc_dk.dk_dev.dv_xname); sc->sc_resets++;}/* dev_t is short, must use prototype syntax */intsdopen(dev_t dev, int flags, int ifmt, struct proc *p){ register int unit = sdunit(dev); register struct sd_softc *sc; if (unit >= sdcd.cd_ndevs || (sc = sdcd.cd_devs[unit]) == NULL) return (ENXIO); if ((sc->sc_flags & SDF_ALIVE) == 0 && suser(p->p_ucred, &p->p_acflag)) return (ENXIO); return (0);}intsdclose(dev_t dev, int flags, int ifmt, struct proc *p){ register struct sd_softc *sc = sdcd.cd_devs[sdunit(dev)]; sc->sc_format_pid = 0; return (0);}/* * This routine is called for partial block transfers and non-aligned * transfers (the latter only being possible on devices with a block size * larger than DEV_BSIZE). The operation is performed in three steps * using a locally allocated buffer: * 1. transfer any initial partial block * 2. transfer full blocks * 3. transfer any final partial block */static voidsdlblkstrat(bp, bsize) register struct buf *bp; register int bsize;{ register int bn, resid, boff, count; register caddr_t addr, cbuf; struct buf *tbp; /* should probably use geteblk() here, but I fear consequences */ cbuf = (caddr_t)malloc(bsize, M_DEVBUF, M_WAITOK); tbp = (struct buf *)malloc(sizeof *tbp, M_DEVBUF, M_WAITOK); bzero((caddr_t)tbp, sizeof *tbp); tbp->b_proc = curproc; tbp->b_dev = bp->b_dev; bn = bp->b_blkno; resid = bp->b_bcount; addr = bp->b_un.b_addr;#ifdef DEBUG if (sddebug & SDB_PARTIAL) printf("sdlblkstrat: bp %x flags %x bn %x resid %x addr %x\n", bp, bp->b_flags, bn, resid, addr);#endif while (resid > 0) { boff = dbtob(bn) & (bsize - 1); if (boff || resid < bsize) { struct sd_softc *sc = sdcd.cd_devs[sdunit(bp->b_dev)]; sc->sc_partials++; count = min(resid, bsize - boff); tbp->b_flags = B_BUSY | B_READ; tbp->b_blkno = bn - btodb(boff); tbp->b_un.b_addr = cbuf; tbp->b_bcount = bsize;#ifdef DEBUG if (sddebug & SDB_PARTIAL) printf(" readahead: bn %x cnt %x off %x addr %x\n", tbp->b_blkno, count, boff, addr);#endif sdstrategy(tbp); biowait(tbp); if (tbp->b_flags & B_ERROR) { bp->b_flags |= B_ERROR; bp->b_error = tbp->b_error; break; } if (bp->b_flags & B_READ) { bcopy(&cbuf[boff], addr, count); goto done; } bcopy(addr, &cbuf[boff], count);#ifdef DEBUG if (sddebug & SDB_PARTIAL) printf(" writeback: bn %x cnt %x off %x addr %x\n", tbp->b_blkno, count, boff, addr);#endif } else { count = resid & ~(bsize - 1); tbp->b_blkno = bn; tbp->b_un.b_addr = addr; tbp->b_bcount = count;#ifdef DEBUG if (sddebug & SDB_PARTIAL) printf(" fulltrans: bn %x cnt %x addr %x\n", tbp->b_blkno, count, addr);#endif } tbp->b_flags = B_BUSY | (bp->b_flags & B_READ); sdstrategy(tbp); biowait(tbp); if (tbp->b_flags & B_ERROR) { bp->b_flags |= B_ERROR; bp->b_error = tbp->b_error;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -