152130Smckusick /* 252130Smckusick * Copyright (c) 1992 Regents of the University of California. 352130Smckusick * All rights reserved. 452130Smckusick * 552130Smckusick * This code is derived from software contributed to Berkeley by 652130Smckusick * Van Jacobson of Lawrence Berkeley Laboratory and Ralph Campbell. 752130Smckusick * 852130Smckusick * %sccs.include.redist.c% 952130Smckusick * 10*54147Sralph * @(#)rz.c 7.4 (Berkeley) 06/20/92 1152130Smckusick */ 1252130Smckusick 1352130Smckusick /* 1452130Smckusick * SCSI CCS (Command Command Set) disk driver. 1553202Sralph * NOTE: The name was changed from "sd" to "rz" for DEC naming compatibility. 1652130Smckusick * I guess I can't avoid confusion someplace. 1752130Smckusick */ 1852130Smckusick #include "rz.h" 1952130Smckusick #if NRZ > 0 2052130Smckusick 2152130Smckusick #include "param.h" 2252130Smckusick #include "systm.h" 2352130Smckusick #include "buf.h" 2452130Smckusick #include "errno.h" 2553202Sralph #include "fcntl.h" 2653202Sralph #include "ioctl.h" 2752130Smckusick #include "dkstat.h" 2852130Smckusick #include "disklabel.h" 2952130Smckusick #include "malloc.h" 3053202Sralph #include "proc.h" 3153202Sralph #include "uio.h" 3253202Sralph #include "stat.h" 3353202Sralph #include "syslog.h" 3453202Sralph #include "ufs/ffs/fs.h" 3552130Smckusick 3652130Smckusick #include "device.h" 3752130Smckusick #include "scsi.h" 3852130Smckusick 3952130Smckusick extern int splbio(); 4052130Smckusick extern void splx(); 4152130Smckusick extern int physio(); 42*54147Sralph extern char *readdisklabel(); 4352130Smckusick 4452130Smckusick int rzprobe(); 4552130Smckusick void rzstrategy(), rzstart(), rzdone(); 4652130Smckusick 4752130Smckusick struct driver rzdriver = { 4852130Smckusick "rz", rzprobe, rzstart, rzdone, 4952130Smckusick }; 5052130Smckusick 5152130Smckusick struct size { 5252130Smckusick u_long strtblk; 5353202Sralph u_long nblocks; 5452130Smckusick }; 5552130Smckusick 5652130Smckusick /* 5752130Smckusick * Since the SCSI standard tends to hide the disk structure, we define 5852130Smckusick * partitions in terms of DEV_BSIZE blocks. The default partition table 5953202Sralph * (for an unlabeled disk) reserves 8K for a boot area, has an 8 meg 6052130Smckusick * root and 32 meg of swap. The rest of the space on the drive goes in 6152130Smckusick * the G partition. As usual, the C partition covers the entire disk 6252130Smckusick * (including the boot area). 6352130Smckusick */ 6453202Sralph struct size rzdefaultpart[MAXPARTITIONS] = { 6553202Sralph 0, 16384, /* A */ 6653202Sralph 16384, 65536, /* B */ 6753202Sralph 0, 0, /* C */ 6853202Sralph 17408, 0, /* D */ 6953202Sralph 115712, 0, /* E */ 7053202Sralph 218112, 0, /* F */ 7153202Sralph 81920, 0, /* G */ 7253202Sralph 115712, 0, /* H */ 7352130Smckusick }; 7452130Smckusick 7553202Sralph #define RAWPART 2 /* 'c' partition */ /* XXX */ 7653202Sralph 7752130Smckusick struct rzstats { 7852130Smckusick long rzresets; 7952130Smckusick long rztransfers; 8052130Smckusick long rzpartials; 8152130Smckusick }; 8252130Smckusick 8352130Smckusick struct rz_softc { 8452130Smckusick struct scsi_device *sc_sd; /* physical unit info */ 8553202Sralph pid_t sc_format_pid; /* process using "format" mode */ 8653202Sralph u_long sc_openpart; /* partitions open */ 8753202Sralph u_long sc_bopenpart; /* block partitions open */ 8853202Sralph u_long sc_copenpart; /* character partitions open */ 8952130Smckusick short sc_flags; /* see below */ 9052130Smckusick short sc_type; /* drive type from INQUIRY cmd */ 9152130Smckusick u_int sc_blks; /* number of blocks on device */ 9252130Smckusick int sc_blksize; /* device block size in bytes */ 9352130Smckusick int sc_bshift; /* convert device blocks to DEV_BSIZE */ 9452130Smckusick u_int sc_wpms; /* average xfer rate in 16bit wds/sec */ 9553202Sralph struct disklabel sc_label; /* disk label for this disk */ 9652130Smckusick struct rzstats sc_stats; /* statisic counts */ 9752130Smckusick struct buf sc_tab; /* queue of pending operations */ 9852130Smckusick struct buf sc_buf; /* buf for doing I/O */ 9952130Smckusick struct buf sc_errbuf; /* buf for doing REQUEST_SENSE */ 10052130Smckusick struct ScsiCmd sc_cmd; /* command for controller */ 10152130Smckusick ScsiGroup1Cmd sc_rwcmd; /* SCSI cmd if not in "format" mode */ 10252130Smckusick struct scsi_fmt_cdb sc_cdb; /* SCSI cmd if in "format" mode */ 10352130Smckusick struct scsi_fmt_sense sc_sense; /* sense data from last cmd */ 10452130Smckusick } rz_softc[NRZ]; 10552130Smckusick 10652130Smckusick /* sc_flags values */ 10753202Sralph #define RZF_ALIVE 0x01 /* drive found and ready */ 10853202Sralph #define RZF_SENSEINPROGRESS 0x02 /* REQUEST_SENSE command in progress */ 10953202Sralph #define RZF_HAVELABEL 0x04 /* valid label found on disk */ 11053202Sralph #define RZF_WLABEL 0x08 /* label is writeable */ 11152130Smckusick 11252130Smckusick #ifdef DEBUG 11352130Smckusick int rzdebug = 3; 11452130Smckusick #define RZB_ERROR 0x01 11552130Smckusick #define RZB_PARTIAL 0x02 11652130Smckusick #define RZB_PRLABEL 0x04 11752130Smckusick #endif 11852130Smckusick 11953202Sralph #define rzunit(x) (minor(x) >> 3) 12052130Smckusick #define rzpart(x) (minor(x) & 0x7) 12152130Smckusick #define b_cylin b_resid 12252130Smckusick 12352130Smckusick /* 12452130Smckusick * Table of scsi commands users are allowed to access via "format" mode. 12552130Smckusick * 0 means not legal. 12652130Smckusick * 1 means legal. 12752130Smckusick */ 12852130Smckusick static char legal_cmds[256] = { 12952130Smckusick /***** 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 13052130Smckusick /*00*/ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13152130Smckusick /*10*/ 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 13252130Smckusick /*20*/ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13352130Smckusick /*30*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13452130Smckusick /*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13552130Smckusick /*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13652130Smckusick /*60*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13752130Smckusick /*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13852130Smckusick /*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13952130Smckusick /*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14052130Smckusick /*a0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14152130Smckusick /*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14252130Smckusick /*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14352130Smckusick /*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14452130Smckusick /*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14552130Smckusick /*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14652130Smckusick }; 14752130Smckusick 14852130Smckusick /* 14952130Smckusick * Test to see if device is present. 15052130Smckusick * Return true if found and initialized ok. 15152130Smckusick */ 15252130Smckusick rzprobe(sd) 15352130Smckusick register struct scsi_device *sd; 15452130Smckusick { 15552130Smckusick register struct rz_softc *sc = &rz_softc[sd->sd_unit]; 15652130Smckusick register int tries, i; 15752130Smckusick ScsiInquiryData inqbuf; 15852130Smckusick u_char capbuf[8]; 15952130Smckusick ScsiClass7Sense *sp; 16052130Smckusick 16152130Smckusick /* init some parameters that don't change */ 16252130Smckusick sc->sc_sd = sd; 16352130Smckusick sc->sc_cmd.sd = sd; 16452130Smckusick sc->sc_cmd.unit = sd->sd_unit; 16552130Smckusick sc->sc_rwcmd.unitNumber = sd->sd_slave; 16652130Smckusick 16752130Smckusick /* try to find out what type of device this is */ 16852130Smckusick sc->sc_format_pid = 1; /* force use of sc_cdb */ 16952130Smckusick sc->sc_cdb.len = sizeof(ScsiGroup0Cmd); 17052130Smckusick scsiGroup0Cmd(SCSI_INQUIRY, sd->sd_slave, 0, sizeof(inqbuf), 17152130Smckusick (ScsiGroup0Cmd *)sc->sc_cdb.cdb); 17252130Smckusick sc->sc_buf.b_flags = B_BUSY | B_PHYS | B_READ; 17352130Smckusick sc->sc_buf.b_bcount = sizeof(inqbuf); 17452130Smckusick sc->sc_buf.b_un.b_addr = (caddr_t)&inqbuf; 17552130Smckusick sc->sc_buf.av_forw = (struct buf *)0; 17652130Smckusick sc->sc_tab.b_actf = sc->sc_tab.b_actl = &sc->sc_buf; 17752130Smckusick rzstart(sd->sd_unit); 17852130Smckusick if (biowait(&sc->sc_buf) || 17952130Smckusick (i = sizeof(inqbuf) - sc->sc_buf.b_resid) < 5) 18052130Smckusick goto bad; 18152130Smckusick switch (inqbuf.type) { 18252130Smckusick case SCSI_DISK_TYPE: /* disk */ 18352130Smckusick case SCSI_WORM_TYPE: /* WORM */ 18452130Smckusick case SCSI_ROM_TYPE: /* CD-ROM */ 18552130Smckusick case SCSI_OPTICAL_MEM_TYPE: /* Magneto-optical */ 18652130Smckusick break; 18752130Smckusick 18852130Smckusick default: /* not a disk */ 18952130Smckusick goto bad; 19052130Smckusick } 19152130Smckusick sc->sc_type = inqbuf.type; 19252130Smckusick 19352130Smckusick /* see if device is ready */ 19452130Smckusick for (tries = 10; ; ) { 19552130Smckusick sc->sc_cdb.len = sizeof(ScsiGroup0Cmd); 19652130Smckusick scsiGroup0Cmd(SCSI_TEST_UNIT_READY, sd->sd_slave, 0, 0, 19752130Smckusick (ScsiGroup0Cmd *)sc->sc_cdb.cdb); 19852130Smckusick sc->sc_buf.b_flags = B_BUSY | B_PHYS | B_READ; 19952130Smckusick sc->sc_buf.b_bcount = 0; 20052130Smckusick sc->sc_buf.b_un.b_addr = (caddr_t)0; 20152130Smckusick sc->sc_buf.av_forw = (struct buf *)0; 20252130Smckusick sc->sc_tab.b_actf = sc->sc_tab.b_actl = &sc->sc_buf; 20352130Smckusick 20452130Smckusick sc->sc_cmd.cmd = sc->sc_cdb.cdb; 20552130Smckusick sc->sc_cmd.cmdlen = sc->sc_cdb.len; 20652130Smckusick sc->sc_cmd.buf = (caddr_t)0; 20752130Smckusick sc->sc_cmd.buflen = 0; 20852130Smckusick /* setup synchronous data transfers if the device supports it */ 20952130Smckusick if (tries == 10 && (inqbuf.flags & SCSI_SYNC)) 21052130Smckusick sc->sc_cmd.flags = SCSICMD_USE_SYNC; 21152130Smckusick else 21252130Smckusick sc->sc_cmd.flags = 0; 21352130Smckusick 21452130Smckusick (*sc->sc_sd->sd_cdriver->d_start)(&sc->sc_cmd); 21552130Smckusick if (!biowait(&sc->sc_buf)) 21652130Smckusick break; 21752130Smckusick if (--tries < 0) 21852130Smckusick goto bad; 21952130Smckusick if (!(sc->sc_sense.status & SCSI_STATUS_CHECKCOND)) 22052130Smckusick goto again; 22152130Smckusick sp = (ScsiClass7Sense *)sc->sc_sense.sense; 22252130Smckusick if (sp->error7 != 0x70) 22352130Smckusick goto again; 22452130Smckusick if (sp->key == SCSI_CLASS7_UNIT_ATTN && tries != 9) { 22552130Smckusick /* drive recalibrating, give it a while */ 22652130Smckusick DELAY(1000000); 22752130Smckusick continue; 22852130Smckusick } 22952130Smckusick if (sp->key == SCSI_CLASS7_NOT_READY) { 23052130Smckusick ScsiStartStopCmd *cp; 23152130Smckusick 23252130Smckusick /* try to spin-up disk with start/stop command */ 23352130Smckusick sc->sc_cdb.len = sizeof(ScsiGroup0Cmd); 23452130Smckusick cp = (ScsiStartStopCmd *)sc->sc_cdb.cdb; 23552130Smckusick cp->command = SCSI_START_STOP; 23652130Smckusick cp->unitNumber = sd->sd_slave; 23752130Smckusick cp->immed = 0; 23852130Smckusick cp->loadEject = 0; 23952130Smckusick cp->start = 1; 24052130Smckusick cp->pad1 = 0; 24152130Smckusick cp->pad2 = 0; 24252130Smckusick cp->pad3 = 0; 24352130Smckusick cp->pad4 = 0; 24452130Smckusick cp->control = 0; 24552130Smckusick sc->sc_buf.b_flags = B_BUSY | B_PHYS | B_READ; 24652130Smckusick sc->sc_buf.b_bcount = 0; 24752130Smckusick sc->sc_buf.b_un.b_addr = (caddr_t)0; 24852130Smckusick sc->sc_buf.av_forw = (struct buf *)0; 24952130Smckusick sc->sc_tab.b_actf = sc->sc_tab.b_actl = &sc->sc_buf; 25052130Smckusick rzstart(sd->sd_unit); 25152130Smckusick if (biowait(&sc->sc_buf)) 25252130Smckusick goto bad; 25352130Smckusick continue; 25452130Smckusick } 25552130Smckusick again: 25652130Smckusick DELAY(1000); 25752130Smckusick } 25852130Smckusick 25952130Smckusick /* find out how big a disk this is */ 26052130Smckusick sc->sc_cdb.len = sizeof(ScsiGroup1Cmd); 26152130Smckusick scsiGroup1Cmd(SCSI_READ_CAPACITY, sd->sd_slave, 0, 0, 26252130Smckusick (ScsiGroup1Cmd *)sc->sc_cdb.cdb); 26352130Smckusick sc->sc_buf.b_flags = B_BUSY | B_PHYS | B_READ; 26452130Smckusick sc->sc_buf.b_bcount = sizeof(capbuf); 26552130Smckusick sc->sc_buf.b_un.b_addr = (caddr_t)capbuf; 26652130Smckusick sc->sc_buf.av_forw = (struct buf *)0; 26752130Smckusick sc->sc_tab.b_actf = sc->sc_tab.b_actl = &sc->sc_buf; 26852130Smckusick rzstart(sd->sd_unit); 26952130Smckusick if (biowait(&sc->sc_buf) || sc->sc_buf.b_resid != 0) 27052130Smckusick goto bad; 27153202Sralph sc->sc_blks = ((capbuf[0] << 24) | (capbuf[1] << 16) | 27253202Sralph (capbuf[2] << 8) | capbuf[3]) + 1; 27352130Smckusick sc->sc_blksize = (capbuf[4] << 24) | (capbuf[5] << 16) | 27452130Smckusick (capbuf[6] << 8) | capbuf[7]; 27552130Smckusick 27652130Smckusick printf("rz%d at %s%d drive %d slave %d", sd->sd_unit, 27752130Smckusick sd->sd_cdriver->d_name, sd->sd_ctlr, sd->sd_drive, 27852130Smckusick sd->sd_slave); 27952130Smckusick if (inqbuf.version > 1 || i < 36) 28052130Smckusick printf(" type 0x%x, qual 0x%x, ver %d", 28152130Smckusick inqbuf.type, inqbuf.qualifier, inqbuf.version); 28252130Smckusick else { 28352130Smckusick char vid[9], pid[17], revl[5]; 28452130Smckusick 28552130Smckusick bcopy((caddr_t)inqbuf.vendorID, (caddr_t)vid, 8); 28652130Smckusick bcopy((caddr_t)inqbuf.productID, (caddr_t)pid, 16); 28752130Smckusick bcopy((caddr_t)inqbuf.revLevel, (caddr_t)revl, 4); 28852130Smckusick for (i = 8; --i > 0; ) 28952130Smckusick if (vid[i] != ' ') 29052130Smckusick break; 29152130Smckusick vid[i+1] = 0; 29252130Smckusick for (i = 16; --i > 0; ) 29352130Smckusick if (pid[i] != ' ') 29452130Smckusick break; 29552130Smckusick pid[i+1] = 0; 29652130Smckusick for (i = 4; --i > 0; ) 29752130Smckusick if (revl[i] != ' ') 29852130Smckusick break; 29952130Smckusick revl[i+1] = 0; 30052130Smckusick printf(" %s %s rev %s", vid, pid, revl); 30152130Smckusick } 30252130Smckusick printf(", %d %d byte blocks\n", sc->sc_blks, sc->sc_blksize); 30352130Smckusick if (sc->sc_blksize != DEV_BSIZE) { 30452130Smckusick if (sc->sc_blksize < DEV_BSIZE) { 30552130Smckusick printf("rz%d: need %d byte blocks - drive ignored\n", 30652130Smckusick sd->sd_unit, DEV_BSIZE); 30752130Smckusick goto bad; 30852130Smckusick } 30952130Smckusick for (i = sc->sc_blksize; i > DEV_BSIZE; i >>= 1) 31052130Smckusick ++sc->sc_bshift; 31152130Smckusick sc->sc_blks <<= sc->sc_bshift; 31252130Smckusick } 31352130Smckusick sc->sc_wpms = 32 * (60 * DEV_BSIZE / 2); /* XXX */ 31452130Smckusick sc->sc_format_pid = 0; 31552130Smckusick sc->sc_flags = RZF_ALIVE; 31652130Smckusick sc->sc_buf.b_flags = 0; 31752130Smckusick return (1); 31852130Smckusick 31952130Smckusick bad: 32052130Smckusick /* doesn't exist or not a CCS device */ 32152130Smckusick sc->sc_format_pid = 0; 32252130Smckusick sc->sc_buf.b_flags = 0; 32352130Smckusick return (0); 32452130Smckusick } 32552130Smckusick 32652130Smckusick /* 32752130Smckusick * This routine is called for partial block transfers and non-aligned 32852130Smckusick * transfers (the latter only being possible on devices with a block size 32952130Smckusick * larger than DEV_BSIZE). The operation is performed in three steps 33052130Smckusick * using a locally allocated buffer: 33152130Smckusick * 1. transfer any initial partial block 33252130Smckusick * 2. transfer full blocks 33352130Smckusick * 3. transfer any final partial block 33452130Smckusick */ 33552130Smckusick static void 33652130Smckusick rzlblkstrat(bp, bsize) 33752130Smckusick register struct buf *bp; 33852130Smckusick register int bsize; 33952130Smckusick { 34052130Smckusick register struct buf *cbp; 34152130Smckusick caddr_t cbuf; 34252130Smckusick register int bn, resid; 34352130Smckusick register caddr_t addr; 34452130Smckusick 34552130Smckusick cbp = (struct buf *)malloc(sizeof(struct buf), M_DEVBUF, M_WAITOK); 34652130Smckusick cbuf = (caddr_t)malloc(bsize, M_DEVBUF, M_WAITOK); 34752130Smckusick bzero((caddr_t)cbp, sizeof(*cbp)); 34852130Smckusick cbp->b_proc = curproc; 34952130Smckusick cbp->b_dev = bp->b_dev; 35052130Smckusick bn = bp->b_blkno; 35152130Smckusick resid = bp->b_bcount; 35252130Smckusick addr = bp->b_un.b_addr; 35352130Smckusick #ifdef DEBUG 35452130Smckusick if (rzdebug & RZB_PARTIAL) 35552130Smckusick printf("rzlblkstrat: bp %x flags %x bn %x resid %x addr %x\n", 35652130Smckusick bp, bp->b_flags, bn, resid, addr); 35752130Smckusick #endif 35852130Smckusick 35952130Smckusick while (resid > 0) { 36052130Smckusick register int boff = dbtob(bn) & (bsize - 1); 36152130Smckusick register int count; 36252130Smckusick 36352130Smckusick if (boff || resid < bsize) { 36452130Smckusick rz_softc[rzunit(bp->b_dev)].sc_stats.rzpartials++; 36552130Smckusick count = MIN(resid, bsize - boff); 36652130Smckusick cbp->b_flags = B_BUSY | B_PHYS | B_READ; 36752130Smckusick cbp->b_blkno = bn - btodb(boff); 36852130Smckusick cbp->b_un.b_addr = cbuf; 36952130Smckusick cbp->b_bcount = bsize; 37052130Smckusick #ifdef DEBUG 37152130Smckusick if (rzdebug & RZB_PARTIAL) 37252130Smckusick printf(" readahead: bn %x cnt %x off %x addr %x\n", 37352130Smckusick cbp->b_blkno, count, boff, addr); 37452130Smckusick #endif 37552130Smckusick rzstrategy(cbp); 37652130Smckusick biowait(cbp); 37752130Smckusick if (cbp->b_flags & B_ERROR) { 37852130Smckusick bp->b_flags |= B_ERROR; 37952130Smckusick bp->b_error = cbp->b_error; 38052130Smckusick break; 38152130Smckusick } 38252130Smckusick if (bp->b_flags & B_READ) { 38352130Smckusick bcopy(&cbuf[boff], addr, count); 38452130Smckusick goto done; 38552130Smckusick } 38652130Smckusick bcopy(addr, &cbuf[boff], count); 38752130Smckusick #ifdef DEBUG 38852130Smckusick if (rzdebug & RZB_PARTIAL) 38952130Smckusick printf(" writeback: bn %x cnt %x off %x addr %x\n", 39052130Smckusick cbp->b_blkno, count, boff, addr); 39152130Smckusick #endif 39252130Smckusick } else { 39352130Smckusick count = resid & ~(bsize - 1); 39452130Smckusick cbp->b_blkno = bn; 39552130Smckusick cbp->b_un.b_addr = addr; 39652130Smckusick cbp->b_bcount = count; 39752130Smckusick #ifdef DEBUG 39852130Smckusick if (rzdebug & RZB_PARTIAL) 39952130Smckusick printf(" fulltrans: bn %x cnt %x addr %x\n", 40052130Smckusick cbp->b_blkno, count, addr); 40152130Smckusick #endif 40252130Smckusick } 40352130Smckusick cbp->b_flags = B_BUSY | B_PHYS | (bp->b_flags & B_READ); 40452130Smckusick rzstrategy(cbp); 40552130Smckusick biowait(cbp); 40652130Smckusick if (cbp->b_flags & B_ERROR) { 40752130Smckusick bp->b_flags |= B_ERROR; 40852130Smckusick bp->b_error = cbp->b_error; 40952130Smckusick break; 41052130Smckusick } 41152130Smckusick done: 41252130Smckusick bn += btodb(count); 41352130Smckusick resid -= count; 41452130Smckusick addr += count; 41552130Smckusick #ifdef DEBUG 41652130Smckusick if (rzdebug & RZB_PARTIAL) 41752130Smckusick printf(" done: bn %x resid %x addr %x\n", 41852130Smckusick bn, resid, addr); 41952130Smckusick #endif 42052130Smckusick } 42152130Smckusick free(cbuf, M_DEVBUF); 42252130Smckusick free(cbp, M_DEVBUF); 42352130Smckusick } 42452130Smckusick 42552130Smckusick void 42652130Smckusick rzstrategy(bp) 42752130Smckusick register struct buf *bp; 42852130Smckusick { 42952130Smckusick register int unit = rzunit(bp->b_dev); 43052130Smckusick register int part = rzpart(bp->b_dev); 43153202Sralph register u_long bn, sz; 43252130Smckusick register struct rz_softc *sc = &rz_softc[unit]; 43353202Sralph register struct partition *pp = &sc->sc_label.d_partitions[part]; 43452130Smckusick register int s; 43552130Smckusick 43652130Smckusick if (sc->sc_format_pid) { 43752130Smckusick if (sc->sc_format_pid != curproc->p_pid) { 43852130Smckusick bp->b_error = EPERM; 43952130Smckusick goto bad; 44052130Smckusick } 44152130Smckusick bp->b_cylin = 0; 44252130Smckusick } else { 44352130Smckusick bn = bp->b_blkno; 44453202Sralph sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT; 44553202Sralph if (bn + sz > pp->p_size) { 44653202Sralph /* if exactly at end of disk, return an EOF */ 44753202Sralph if (bn == pp->p_size) { 44852130Smckusick bp->b_resid = bp->b_bcount; 44952130Smckusick goto done; 45052130Smckusick } 45153202Sralph /* if none of it fits, error */ 45253202Sralph if (bn >= pp->p_size) { 45353202Sralph bp->b_error = EINVAL; 45453202Sralph goto bad; 45553202Sralph } 45653202Sralph /* otherwise, truncate */ 45753202Sralph sz = pp->p_size - bn; 45853202Sralph bp->b_bcount = sz << DEV_BSHIFT; 45953202Sralph } 46053202Sralph /* check for write to write protected label */ 46153202Sralph if (bn + pp->p_offset <= LABELSECTOR && 46253202Sralph #if LABELSECTOR != 0 46353202Sralph bn + pp->p_offset + sz > LABELSECTOR && 46453202Sralph #endif 46553202Sralph !(bp->b_flags & B_READ) && !(sc->sc_flags & RZF_WLABEL)) { 46653202Sralph bp->b_error = EROFS; 46752130Smckusick goto bad; 46852130Smckusick } 46952130Smckusick /* 47052130Smckusick * Non-aligned or partial-block transfers handled specially. 47152130Smckusick */ 47252130Smckusick s = sc->sc_blksize - 1; 47352130Smckusick if ((dbtob(bn) & s) || (bp->b_bcount & s)) { 47452130Smckusick rzlblkstrat(bp, sc->sc_blksize); 47552130Smckusick goto done; 47652130Smckusick } 47753202Sralph bp->b_cylin = (bn + pp->p_offset) >> sc->sc_bshift; 47852130Smckusick } 47952130Smckusick /* don't let disksort() see sc_errbuf */ 48052130Smckusick while (sc->sc_flags & RZF_SENSEINPROGRESS) 48152130Smckusick printf("SENSE\n"); /* XXX */ 48252130Smckusick s = splbio(); 48352130Smckusick disksort(&sc->sc_tab, bp); 48452130Smckusick if (sc->sc_tab.b_active == 0) { 48552130Smckusick sc->sc_tab.b_active = 1; 48652130Smckusick rzstart(unit); 48752130Smckusick } 48852130Smckusick splx(s); 48952130Smckusick return; 49052130Smckusick bad: 49152130Smckusick bp->b_flags |= B_ERROR; 49252130Smckusick done: 49352130Smckusick biodone(bp); 49452130Smckusick } 49552130Smckusick 49652130Smckusick void 49752130Smckusick rzstart(unit) 49852130Smckusick int unit; 49952130Smckusick { 50052130Smckusick register struct rz_softc *sc = &rz_softc[unit]; 50152130Smckusick register struct buf *bp = sc->sc_tab.b_actf; 50252130Smckusick register int n; 50352130Smckusick 50452130Smckusick sc->sc_cmd.buf = bp->b_un.b_addr; 50552130Smckusick sc->sc_cmd.buflen = bp->b_bcount; 50652130Smckusick 50752130Smckusick if (sc->sc_format_pid || (sc->sc_flags & RZF_SENSEINPROGRESS)) { 50852130Smckusick sc->sc_cmd.flags = !(bp->b_flags & B_READ) ? 50952130Smckusick SCSICMD_DATA_TO_DEVICE : 0; 51052130Smckusick sc->sc_cmd.cmd = sc->sc_cdb.cdb; 51152130Smckusick sc->sc_cmd.cmdlen = sc->sc_cdb.len; 51252130Smckusick } else { 51352130Smckusick if (bp->b_flags & B_READ) { 51452130Smckusick sc->sc_cmd.flags = 0; 51552130Smckusick sc->sc_rwcmd.command = SCSI_READ_EXT; 51652130Smckusick } else { 51752130Smckusick sc->sc_cmd.flags = SCSICMD_DATA_TO_DEVICE; 51852130Smckusick sc->sc_rwcmd.command = SCSI_WRITE_EXT; 51952130Smckusick } 52052130Smckusick sc->sc_cmd.cmd = (u_char *)&sc->sc_rwcmd; 52152130Smckusick sc->sc_cmd.cmdlen = sizeof(sc->sc_rwcmd); 52252130Smckusick n = bp->b_cylin; 52352130Smckusick sc->sc_rwcmd.highAddr = n >> 24; 52452130Smckusick sc->sc_rwcmd.midHighAddr = n >> 16; 52552130Smckusick sc->sc_rwcmd.midLowAddr = n >> 8; 52652130Smckusick sc->sc_rwcmd.lowAddr = n; 52752130Smckusick n = howmany(bp->b_bcount, sc->sc_blksize); 52852130Smckusick sc->sc_rwcmd.highBlockCount = n >> 8; 52952130Smckusick sc->sc_rwcmd.lowBlockCount = n; 53052130Smckusick #ifdef DEBUG 53152130Smckusick if ((bp->b_bcount & (sc->sc_blksize - 1)) != 0) 53252130Smckusick printf("rz%d: partial block xfer -- %x bytes\n", 53352130Smckusick unit, bp->b_bcount); 53452130Smckusick #endif 53552130Smckusick sc->sc_stats.rztransfers++; 53652130Smckusick if ((n = sc->sc_sd->sd_dk) >= 0) { 53752130Smckusick dk_busy |= 1 << n; 53852130Smckusick ++dk_seek[n]; 53952130Smckusick ++dk_xfer[n]; 54052130Smckusick dk_wds[n] += bp->b_bcount >> 6; 54152130Smckusick } 54252130Smckusick } 54352130Smckusick 54452130Smckusick /* tell controller to start this command */ 54552130Smckusick (*sc->sc_sd->sd_cdriver->d_start)(&sc->sc_cmd); 54652130Smckusick } 54752130Smckusick 54852130Smckusick /* 54952130Smckusick * This is called by the controller driver when the command is done. 55052130Smckusick */ 55152130Smckusick void 55252130Smckusick rzdone(unit, error, resid, status) 55352130Smckusick register int unit; 55452130Smckusick int error; /* error number from errno.h */ 55552130Smckusick int resid; /* amount not transfered */ 55652130Smckusick int status; /* SCSI status byte */ 55752130Smckusick { 55852130Smckusick register struct rz_softc *sc = &rz_softc[unit]; 55952130Smckusick register struct buf *bp = sc->sc_tab.b_actf; 56052130Smckusick register struct scsi_device *sd = sc->sc_sd; 56152130Smckusick extern int cold; 56252130Smckusick 56352130Smckusick if (bp == NULL) { 56452130Smckusick printf("rz%d: bp == NULL\n", unit); 56552130Smckusick return; 56652130Smckusick } 56752130Smckusick if (sd->sd_dk >= 0) 56852130Smckusick dk_busy &= ~(1 << sd->sd_dk); 56952130Smckusick if (sc->sc_flags & RZF_SENSEINPROGRESS) { 57052130Smckusick sc->sc_flags &= ~RZF_SENSEINPROGRESS; 57152130Smckusick sc->sc_tab.b_actf = bp = bp->av_forw; /* remove sc_errbuf */ 57252130Smckusick 57352130Smckusick if (error || (status & SCSI_STATUS_CHECKCOND)) { 57452130Smckusick #ifdef DEBUG 57552130Smckusick if (rzdebug & RZB_ERROR) 57652130Smckusick printf("rz%d: error reading sense data: error %d scsi status 0x%x\n", 57752130Smckusick unit, error, status); 57852130Smckusick #endif 57952130Smckusick /* 58052130Smckusick * We got an error during the REQUEST_SENSE, 58152130Smckusick * fill in no sense for data. 58252130Smckusick */ 58352130Smckusick sc->sc_sense.sense[0] = 0x70; 58452130Smckusick sc->sc_sense.sense[2] = SCSI_CLASS7_NO_SENSE; 58553083Sralph } else if (!cold) { 58652130Smckusick printf("rz%d: ", unit); 58752130Smckusick scsiPrintSense((ScsiClass7Sense *)sc->sc_sense.sense, 58852130Smckusick sizeof(sc->sc_sense.sense) - resid); 58952130Smckusick } 59052130Smckusick } else if (error || (status & SCSI_STATUS_CHECKCOND)) { 59152130Smckusick #ifdef DEBUG 59253083Sralph if (!cold && (rzdebug & RZB_ERROR)) 59352130Smckusick printf("rz%d: error %d scsi status 0x%x\n", 59452130Smckusick unit, error, status); 59552130Smckusick #endif 59652130Smckusick /* save error info */ 59752130Smckusick sc->sc_sense.status = status; 59852130Smckusick bp->b_flags |= B_ERROR; 59952130Smckusick bp->b_error = error; 60052130Smckusick bp->b_resid = resid; 60152130Smckusick 60252130Smckusick if (status & SCSI_STATUS_CHECKCOND) { 60352130Smckusick /* 60452130Smckusick * Start a REQUEST_SENSE command. 60552130Smckusick * Since we are called at interrupt time, we can't 60652130Smckusick * wait for the command to finish; that's why we use 60752130Smckusick * the sc_flags field. 60852130Smckusick */ 60952130Smckusick sc->sc_flags |= RZF_SENSEINPROGRESS; 61052130Smckusick sc->sc_cdb.len = sizeof(ScsiGroup0Cmd); 61152130Smckusick scsiGroup0Cmd(SCSI_REQUEST_SENSE, sd->sd_slave, 0, 61252130Smckusick sizeof(sc->sc_sense.sense), 61352130Smckusick (ScsiGroup0Cmd *)sc->sc_cdb.cdb); 61452130Smckusick sc->sc_errbuf.b_flags = B_BUSY | B_PHYS | B_READ; 61552130Smckusick sc->sc_errbuf.b_bcount = sizeof(sc->sc_sense.sense); 61652130Smckusick sc->sc_errbuf.b_un.b_addr = (caddr_t)sc->sc_sense.sense; 61752130Smckusick sc->sc_errbuf.av_forw = bp; 61852130Smckusick sc->sc_tab.b_actf = &sc->sc_errbuf; 61952130Smckusick rzstart(unit); 62052130Smckusick return; 62152130Smckusick } 62252130Smckusick } else { 62352130Smckusick sc->sc_sense.status = status; 62452130Smckusick bp->b_resid = resid; 62552130Smckusick } 62652130Smckusick 62752130Smckusick sc->sc_tab.b_actf = bp->av_forw; 62852130Smckusick biodone(bp); 62952130Smckusick if (sc->sc_tab.b_actf) 63052130Smckusick rzstart(unit); 63153202Sralph else { 63252130Smckusick sc->sc_tab.b_active = 0; 63353202Sralph /* finish close protocol */ 63453202Sralph if (sc->sc_openpart == 0) 63553202Sralph wakeup((caddr_t)&sc->sc_tab); 63653202Sralph } 63752130Smckusick } 63852130Smckusick 63952130Smckusick int 64052130Smckusick rzopen(dev, flags, mode, p) 64152130Smckusick dev_t dev; 64252130Smckusick int flags, mode; 64352130Smckusick struct proc *p; 64452130Smckusick { 64552130Smckusick register int unit = rzunit(dev); 64652130Smckusick register struct rz_softc *sc = &rz_softc[unit]; 64753202Sralph register struct disklabel *lp; 64853202Sralph register int i; 64953202Sralph char *err_msg; 65053202Sralph int part; 65153202Sralph u_long mask; 65252130Smckusick 65353202Sralph if (unit >= NRZ || !(sc->sc_flags & RZF_ALIVE)) 65452130Smckusick return (ENXIO); 65553202Sralph 65653202Sralph /* try to read disk label and partition table information */ 65753202Sralph part = rzpart(dev); 65853202Sralph lp = &sc->sc_label; 65953202Sralph if (!(sc->sc_flags & RZF_HAVELABEL)) { 66053202Sralph sc->sc_flags |= RZF_HAVELABEL; 66153202Sralph lp->d_secsize = DEV_BSIZE; 66253202Sralph lp->d_secpercyl = 1 << sc->sc_bshift; 66353202Sralph lp->d_npartitions = MAXPARTITIONS; 66453202Sralph lp->d_partitions[part].p_offset = 0; 66553202Sralph lp->d_partitions[part].p_size = sc->sc_blks; 66653202Sralph if (err_msg = readdisklabel(dev, rzstrategy, lp)) { 66753202Sralph printf("rz%d: %s\n", unit, err_msg); 66853202Sralph sc->sc_label.d_magic = DISKMAGIC; 66953202Sralph sc->sc_label.d_magic2 = DISKMAGIC; 67053202Sralph sc->sc_label.d_type = DTYPE_SCSI; 67153202Sralph sc->sc_label.d_subtype = 0; 67253202Sralph sc->sc_label.d_typename[0] = '\0'; 67353202Sralph sc->sc_label.d_secsize = DEV_BSIZE; 67453202Sralph sc->sc_label.d_secperunit = sc->sc_blks; 67553202Sralph sc->sc_label.d_npartitions = MAXPARTITIONS; 67653202Sralph sc->sc_label.d_bbsize = BBSIZE; 67753202Sralph sc->sc_label.d_sbsize = SBSIZE; 67853202Sralph for (i = 0; i < MAXPARTITIONS; i++) { 67953202Sralph sc->sc_label.d_partitions[i].p_size = 68053202Sralph rzdefaultpart[i].nblocks; 68153202Sralph sc->sc_label.d_partitions[i].p_offset = 68253202Sralph rzdefaultpart[i].strtblk; 68353202Sralph } 68453202Sralph sc->sc_label.d_partitions[RAWPART].p_size = 68553202Sralph sc->sc_blks; 68653202Sralph } 68753202Sralph } 68853202Sralph 68953202Sralph if (part >= lp->d_npartitions || lp->d_partitions[part].p_size == 0) 69052130Smckusick return (ENXIO); 69153202Sralph /* 69253202Sralph * Warn if a partition is opened that overlaps another 69353202Sralph * already open, unless either is the `raw' partition 69453202Sralph * (whole disk). 69553202Sralph */ 69653202Sralph mask = 1 << part; 69753202Sralph if ((sc->sc_openpart & mask) == 0 && part != RAWPART) { 69853202Sralph register struct partition *pp; 69953202Sralph u_long start, end; 70052130Smckusick 70153202Sralph pp = &lp->d_partitions[part]; 70253202Sralph start = pp->p_offset; 70353202Sralph end = pp->p_offset + pp->p_size; 70453202Sralph for (pp = lp->d_partitions, i = 0; 70553202Sralph i < lp->d_npartitions; pp++, i++) { 70653202Sralph if (pp->p_offset + pp->p_size <= start || 70753202Sralph pp->p_offset >= end || i == RAWPART) 70853202Sralph continue; 70953202Sralph if (sc->sc_openpart & (1 << i)) 71053202Sralph log(LOG_WARNING, 71153202Sralph "rz%d%c: overlaps open partition (%c)\n", 71253202Sralph unit, part + 'a', i + 'a'); 71353202Sralph } 71453202Sralph } 71553202Sralph switch (mode) { 71653202Sralph case S_IFCHR: 71753202Sralph sc->sc_copenpart |= mask; 71853202Sralph break; 71953202Sralph case S_IFBLK: 72053202Sralph sc->sc_bopenpart |= mask; 72153202Sralph break; 72253202Sralph } 72353202Sralph sc->sc_openpart |= mask; 72452130Smckusick if (sc->sc_sd->sd_dk >= 0) 72552130Smckusick dk_wpms[sc->sc_sd->sd_dk] = sc->sc_wpms; 72652130Smckusick return (0); 72752130Smckusick } 72852130Smckusick 72953202Sralph rzclose(dev, flags, mode) 73052130Smckusick dev_t dev; 73153202Sralph int flags, mode; 73252130Smckusick { 73353202Sralph register struct rz_softc *sc = &rz_softc[rzunit(dev)]; 73453202Sralph u_long mask = (1 << rzpart(dev)); 73553202Sralph int s; 73653202Sralph 73753202Sralph switch (mode) { 73853202Sralph case S_IFCHR: 73953202Sralph sc->sc_copenpart &= ~mask; 74053202Sralph break; 74153202Sralph case S_IFBLK: 74253202Sralph sc->sc_bopenpart &= ~mask; 74353202Sralph break; 74453202Sralph } 74553202Sralph sc->sc_openpart = sc->sc_copenpart | sc->sc_bopenpart; 74653202Sralph 74753202Sralph /* 74853202Sralph * Should wait for I/O to complete on this partition even if 74953202Sralph * others are open, but wait for work on blkflush(). 75053202Sralph */ 75153202Sralph if (sc->sc_openpart == 0) { 75253202Sralph s = splbio(); 75353202Sralph while (sc->sc_tab.b_actf) 75453202Sralph sleep((caddr_t)&sc->sc_tab, PZERO - 1); 75553202Sralph splx(s); 75653202Sralph sc->sc_flags &= ~RZF_WLABEL; 75753202Sralph } 75852130Smckusick return (0); 75952130Smckusick } 76052130Smckusick 76152130Smckusick int 76252130Smckusick rzread(dev, uio) 76352130Smckusick dev_t dev; 76452130Smckusick struct uio *uio; 76552130Smckusick { 76652130Smckusick register struct rz_softc *sc = &rz_softc[rzunit(dev)]; 76752130Smckusick 76852130Smckusick if (sc->sc_format_pid && sc->sc_format_pid != curproc->p_pid) 76952130Smckusick return (EPERM); 77052130Smckusick 77152130Smckusick return (physio(rzstrategy, (struct buf *)0, dev, 77252130Smckusick B_READ, minphys, uio)); 77352130Smckusick } 77452130Smckusick 77552130Smckusick int 77652130Smckusick rzwrite(dev, uio) 77752130Smckusick dev_t dev; 77852130Smckusick struct uio *uio; 77952130Smckusick { 78052130Smckusick register struct rz_softc *sc = &rz_softc[rzunit(dev)]; 78152130Smckusick 78252130Smckusick if (sc->sc_format_pid && sc->sc_format_pid != curproc->p_pid) 78352130Smckusick return (EPERM); 78452130Smckusick 78552130Smckusick return (physio(rzstrategy, (struct buf *)0, dev, 78652130Smckusick B_WRITE, minphys, uio)); 78752130Smckusick } 78852130Smckusick 78952130Smckusick int 79052130Smckusick rzioctl(dev, cmd, data, flag, p) 79152130Smckusick dev_t dev; 79252130Smckusick int cmd; 79352130Smckusick caddr_t data; 79452130Smckusick int flag; 79552130Smckusick struct proc *p; 79652130Smckusick { 79752130Smckusick register struct rz_softc *sc = &rz_softc[rzunit(dev)]; 79853202Sralph int error; 79953202Sralph int flags; 80052130Smckusick 80152130Smckusick switch (cmd) { 80252130Smckusick default: 80352130Smckusick return (EINVAL); 80452130Smckusick 80552130Smckusick case SDIOCSFORMAT: 80652130Smckusick /* take this device into or out of "format" mode */ 80752130Smckusick if (suser(p->p_ucred, &p->p_acflag)) 80852130Smckusick return (EPERM); 80952130Smckusick 81052130Smckusick if (*(int *)data) { 81152130Smckusick if (sc->sc_format_pid) 81252130Smckusick return (EPERM); 81352130Smckusick sc->sc_format_pid = p->p_pid; 81452130Smckusick } else 81552130Smckusick sc->sc_format_pid = 0; 81652130Smckusick return (0); 81752130Smckusick 81852130Smckusick case SDIOCGFORMAT: 81952130Smckusick /* find out who has the device in format mode */ 82052130Smckusick *(int *)data = sc->sc_format_pid; 82152130Smckusick return (0); 82252130Smckusick 82352130Smckusick case SDIOCSCSICOMMAND: 82452130Smckusick /* 82552130Smckusick * Save what user gave us as SCSI cdb to use with next 82652130Smckusick * read or write to the char device. 82752130Smckusick */ 82852130Smckusick if (sc->sc_format_pid != p->p_pid) 82952130Smckusick return (EPERM); 83052130Smckusick if (legal_cmds[((struct scsi_fmt_cdb *)data)->cdb[0]] == 0) 83152130Smckusick return (EINVAL); 83252130Smckusick bcopy(data, (caddr_t)&sc->sc_cdb, sizeof(sc->sc_cdb)); 83352130Smckusick return (0); 83452130Smckusick 83552130Smckusick case SDIOCSENSE: 83652130Smckusick /* 83752130Smckusick * return the SCSI sense data saved after the last 83852130Smckusick * operation that completed with "check condition" status. 83952130Smckusick */ 84052130Smckusick bcopy((caddr_t)&sc->sc_sense, data, sizeof(sc->sc_sense)); 84152130Smckusick return (0); 84252130Smckusick 84353202Sralph case DIOCGDINFO: 84453202Sralph /* get the current disk label */ 84553202Sralph *(struct disklabel *)data = sc->sc_label; 84653202Sralph return (0); 84753202Sralph 84853202Sralph case DIOCSDINFO: 84953202Sralph /* set the current disk label */ 85053202Sralph if (!(flag & FWRITE)) 85153202Sralph return (EBADF); 85253202Sralph return (setdisklabel(&sc->sc_label, 85353202Sralph (struct disklabel *)data, 85453202Sralph (sc->sc_flags & RZF_WLABEL) ? 0 : sc->sc_openpart)); 85553202Sralph 85653202Sralph #if 0 85753202Sralph case DIOCGPART: 85853202Sralph /* return the disk partition data */ 85953202Sralph ((struct partinfo *)data)->disklab = &sc->sc_label; 86053202Sralph ((struct partinfo *)data)->part = 86153202Sralph &sc->sc_label.d_partitions[rzpart(dev)]; 86253202Sralph return (0); 86353202Sralph #endif 86453202Sralph 86553202Sralph case DIOCWLABEL: 86653202Sralph if (!(flag & FWRITE)) 86753202Sralph return (EBADF); 86853202Sralph if (*(int *)data) 86953202Sralph sc->sc_flags |= RZF_WLABEL; 87053202Sralph else 87153202Sralph sc->sc_flags &= ~RZF_WLABEL; 87253202Sralph return (0); 87353202Sralph 87453202Sralph case DIOCWDINFO: 87553202Sralph /* write the disk label to disk */ 87653202Sralph if (!(flag & FWRITE)) 87753202Sralph return (EBADF); 87853202Sralph error = setdisklabel(&sc->sc_label, 87953202Sralph (struct disklabel *)data, 88053202Sralph (sc->sc_flags & RZF_WLABEL) ? 0 : sc->sc_openpart); 88153202Sralph if (error) 88253202Sralph return (error); 88353202Sralph 88453202Sralph /* simulate opening partition 0 so write succeeds */ 88553202Sralph flags = sc->sc_flags; 88653202Sralph sc->sc_flags = RZF_ALIVE | RZF_WLABEL; 88753202Sralph error = writedisklabel(dev, rzstrategy, &sc->sc_label); 88853202Sralph sc->sc_flags = flags; 88953202Sralph return (error); 89052130Smckusick } 89152130Smckusick /*NOTREACHED*/ 89252130Smckusick } 89352130Smckusick 89452130Smckusick int 89552130Smckusick rzsize(dev) 89652130Smckusick dev_t dev; 89752130Smckusick { 89852130Smckusick register int unit = rzunit(dev); 89953202Sralph register int part = rzpart(dev); 90052130Smckusick register struct rz_softc *sc = &rz_softc[unit]; 90152130Smckusick 90253202Sralph if (unit >= NRZ || !(sc->sc_flags & RZF_ALIVE) || 90353202Sralph part >= sc->sc_label.d_npartitions) 90452130Smckusick return (-1); 90552130Smckusick 90653202Sralph return (sc->sc_label.d_partitions[part].p_size); 90752130Smckusick } 90852130Smckusick 90952130Smckusick /* 91052130Smckusick * Non-interrupt driven, non-dma dump routine. 91152130Smckusick */ 91252130Smckusick int 91352130Smckusick rzdump(dev) 91452130Smckusick dev_t dev; 91552130Smckusick { 91652130Smckusick #ifdef notdef 91752130Smckusick int part = rzpart(dev); 91852130Smckusick int unit = rzunit(dev); 91952130Smckusick register struct rz_softc *sc = &rz_softc[unit]; 92052130Smckusick register struct scsi_device *sd = sc->sc_hd; 92152130Smckusick register daddr_t baddr; 92252130Smckusick register int maddr; 92352130Smckusick register int pages, i; 92452130Smckusick int stat; 92552130Smckusick extern int lowram; 92652130Smckusick 92752130Smckusick /* 92852130Smckusick * Hmm... all vax drivers dump maxfree pages which is physmem minus 92952130Smckusick * the message buffer. Is there a reason for not dumping the 93052130Smckusick * message buffer? Savecore expects to read 'dumpsize' pages of 93152130Smckusick * dump, where dumpsys() sets dumpsize to physmem! 93252130Smckusick */ 93352130Smckusick pages = physmem; 93452130Smckusick 93552130Smckusick /* is drive ok? */ 93652130Smckusick if (unit >= NRZ || (sc->sc_flags & RZF_ALIVE) == 0) 93752130Smckusick return (ENXIO); 93852130Smckusick /* dump parameters in range? */ 93952130Smckusick if (dumplo < 0 || dumplo >= sc->sc_info.part[part].nblocks) 94052130Smckusick return (EINVAL); 94152130Smckusick if (dumplo + ctod(pages) > sc->sc_info.part[part].nblocks) 94252130Smckusick pages = dtoc(sc->sc_info.part[part].nblocks - dumplo); 94352130Smckusick maddr = lowram; 94452130Smckusick baddr = dumplo + sc->sc_info.part[part].strtblk; 94552130Smckusick /* scsi bus idle? */ 94652130Smckusick if (!scsireq(&sc->sc_dq)) { 94752130Smckusick scsireset(sd->sd_ctlr); 94852130Smckusick sc->sc_stats.rzresets++; 94952130Smckusick printf("[ drive %d reset ] ", unit); 95052130Smckusick } 95152130Smckusick for (i = 0; i < pages; i++) { 95252130Smckusick #define NPGMB (1024*1024/NBPG) 95352130Smckusick /* print out how many Mbs we have dumped */ 95452130Smckusick if (i && (i % NPGMB) == 0) 95552130Smckusick printf("%d ", i / NPGMB); 95652130Smckusick #undef NPBMG 95752130Smckusick mapin(mmap, (u_int)vmmap, btop(maddr), PG_URKR|PG_CI|PG_V); 95852130Smckusick stat = scsi_tt_write(sd->sd_ctlr, sd->sd_drive, sd->sd_slave, 95952130Smckusick vmmap, NBPG, baddr, sc->sc_bshift); 96052130Smckusick if (stat) { 96152130Smckusick printf("rzdump: scsi write error 0x%x\n", stat); 96252130Smckusick return (EIO); 96352130Smckusick } 96452130Smckusick maddr += NBPG; 96552130Smckusick baddr += ctod(1); 96652130Smckusick } 96752130Smckusick return (0); 96852130Smckusick #else notdef 96952130Smckusick return (ENXIO); 97052130Smckusick #endif notdef 97152130Smckusick } 97252130Smckusick #endif 973