152130Smckusick /* 264089Sbostic * Copyright (c) 1992, 1993 364089Sbostic * The Regents of the University of California. 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*67478Smckusick * @(#)rz.c 8.2 (Berkeley) 07/03/94 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 2156522Sbostic #include <sys/param.h> 2256522Sbostic #include <sys/systm.h> 2356522Sbostic #include <sys/buf.h> 2456522Sbostic #include <sys/errno.h> 2556522Sbostic #include <sys/fcntl.h> 2656522Sbostic #include <sys/ioctl.h> 2756522Sbostic #include <sys/dkstat.h> 2856522Sbostic #include <sys/disklabel.h> 2956522Sbostic #include <sys/malloc.h> 3056522Sbostic #include <sys/proc.h> 3156522Sbostic #include <sys/uio.h> 3256522Sbostic #include <sys/stat.h> 3356522Sbostic #include <sys/syslog.h> 3452130Smckusick 3556522Sbostic #include <ufs/ffs/fs.h> 3652130Smckusick 3756525Sbostic #include <pmax/dev/device.h> 3856525Sbostic #include <pmax/dev/scsi.h> 3956522Sbostic 4052130Smckusick extern int splbio(); 4152130Smckusick extern void splx(); 4252130Smckusick extern int physio(); 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 */ 6456629Sralph static 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; 17556629Sralph sc->sc_buf.b_actf = (struct buf *)0; 17656629Sralph sc->sc_tab.b_actf = &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; 20156629Sralph sc->sc_buf.b_actf = (struct buf *)0; 20256629Sralph sc->sc_tab.b_actf = &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; 24856629Sralph sc->sc_buf.b_actf = (struct buf *)0; 24956629Sralph sc->sc_tab.b_actf = &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; 26656629Sralph sc->sc_buf.b_actf = (struct buf *)0; 26756629Sralph sc->sc_tab.b_actf = &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); 279*67478Smckusick if (inqbuf.version > 2 || 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++; 36555746Sralph 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); 43152130Smckusick register struct rz_softc *sc = &rz_softc[unit]; 43253202Sralph register struct partition *pp = &sc->sc_label.d_partitions[part]; 43356629Sralph register daddr_t bn; 43456629Sralph register long sz, 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; 44456629Sralph sz = howmany(bp->b_bcount, DEV_BSIZE); 44556629Sralph if ((unsigned)bn + sz > pp->p_size) { 44656629Sralph sz = pp->p_size - bn; 44753202Sralph /* if exactly at end of disk, return an EOF */ 44856629Sralph if (sz == 0) { 44952130Smckusick bp->b_resid = bp->b_bcount; 45052130Smckusick goto done; 45152130Smckusick } 45253202Sralph /* if none of it fits, error */ 45356629Sralph if (sz < 0) { 45453202Sralph bp->b_error = EINVAL; 45553202Sralph goto bad; 45653202Sralph } 45753202Sralph /* otherwise, truncate */ 45856629Sralph bp->b_bcount = dbtob(sz); 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; 57156629Sralph sc->sc_tab.b_actf = bp = bp->b_actf; /* 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; 61756629Sralph sc->sc_errbuf.b_actf = 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 62756629Sralph sc->sc_tab.b_actf = bp->b_actf; 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 63964088Smckusick /* 64064088Smckusick * Read or constuct a disklabel 64164088Smckusick */ 64264088Smckusick void 64364088Smckusick rzgetinfo(dev) 64464088Smckusick dev_t dev; 64564088Smckusick { 64664088Smckusick register int unit = rzunit(dev); 64764088Smckusick register struct rz_softc *sc = &rz_softc[unit]; 64864088Smckusick register struct disklabel *lp = &sc->sc_label; 64964088Smckusick register int i; 65064088Smckusick char *msg; 65164088Smckusick int part; 65264088Smckusick extern char *readdisklabel(); 65364088Smckusick 65464088Smckusick part = rzpart(dev); 65564088Smckusick sc->sc_flags |= RZF_HAVELABEL; 65664088Smckusick 65764088Smckusick lp->d_type = DTYPE_SCSI; 65864088Smckusick lp->d_secsize = DEV_BSIZE; 65964088Smckusick lp->d_secpercyl = 1 << sc->sc_bshift; 66064088Smckusick lp->d_npartitions = MAXPARTITIONS; 66164088Smckusick lp->d_partitions[part].p_offset = 0; 66264088Smckusick lp->d_partitions[part].p_size = sc->sc_blks; 66364088Smckusick 66464088Smckusick /* 66564088Smckusick * Now try to read the disklabel 66664088Smckusick */ 66764088Smckusick msg = readdisklabel(dev, rzstrategy, lp); 66864088Smckusick if (msg == NULL) 66964088Smckusick return; 67064088Smckusick 67164088Smckusick printf("rz%d: WARNING: %s\n", unit, msg); 67264088Smckusick sc->sc_label.d_magic = DISKMAGIC; 67364088Smckusick sc->sc_label.d_magic2 = DISKMAGIC; 67464088Smckusick sc->sc_label.d_type = DTYPE_SCSI; 67564088Smckusick sc->sc_label.d_subtype = 0; 67664088Smckusick sc->sc_label.d_typename[0] = '\0'; 67764088Smckusick sc->sc_label.d_secsize = DEV_BSIZE; 67864088Smckusick sc->sc_label.d_secperunit = sc->sc_blks; 67964088Smckusick sc->sc_label.d_npartitions = MAXPARTITIONS; 68064088Smckusick sc->sc_label.d_bbsize = BBSIZE; 68164088Smckusick sc->sc_label.d_sbsize = SBSIZE; 68264088Smckusick for (i = 0; i < MAXPARTITIONS; i++) { 68364088Smckusick sc->sc_label.d_partitions[i].p_size = 68464088Smckusick rzdefaultpart[i].nblocks; 68564088Smckusick sc->sc_label.d_partitions[i].p_offset = 68664088Smckusick rzdefaultpart[i].strtblk; 68764088Smckusick } 68864088Smckusick sc->sc_label.d_partitions[RAWPART].p_size = sc->sc_blks; 68964088Smckusick } 69064088Smckusick 69152130Smckusick int 69252130Smckusick rzopen(dev, flags, mode, p) 69352130Smckusick dev_t dev; 69452130Smckusick int flags, mode; 69552130Smckusick struct proc *p; 69652130Smckusick { 69752130Smckusick register int unit = rzunit(dev); 69852130Smckusick register struct rz_softc *sc = &rz_softc[unit]; 69953202Sralph register struct disklabel *lp; 70053202Sralph register int i; 70153202Sralph int part; 70253202Sralph u_long mask; 70352130Smckusick 70453202Sralph if (unit >= NRZ || !(sc->sc_flags & RZF_ALIVE)) 70552130Smckusick return (ENXIO); 70653202Sralph 70753202Sralph /* try to read disk label and partition table information */ 70853202Sralph part = rzpart(dev); 70964088Smckusick if (!(sc->sc_flags & RZF_HAVELABEL)) 71064088Smckusick rzgetinfo(dev); 71164088Smckusick 71253202Sralph lp = &sc->sc_label; 71353202Sralph if (part >= lp->d_npartitions || lp->d_partitions[part].p_size == 0) 71452130Smckusick return (ENXIO); 71553202Sralph /* 71653202Sralph * Warn if a partition is opened that overlaps another 71753202Sralph * already open, unless either is the `raw' partition 71853202Sralph * (whole disk). 71953202Sralph */ 72053202Sralph mask = 1 << part; 72153202Sralph if ((sc->sc_openpart & mask) == 0 && part != RAWPART) { 72253202Sralph register struct partition *pp; 72353202Sralph u_long start, end; 72452130Smckusick 72553202Sralph pp = &lp->d_partitions[part]; 72653202Sralph start = pp->p_offset; 72753202Sralph end = pp->p_offset + pp->p_size; 72853202Sralph for (pp = lp->d_partitions, i = 0; 72953202Sralph i < lp->d_npartitions; pp++, i++) { 73053202Sralph if (pp->p_offset + pp->p_size <= start || 73153202Sralph pp->p_offset >= end || i == RAWPART) 73253202Sralph continue; 73353202Sralph if (sc->sc_openpart & (1 << i)) 73453202Sralph log(LOG_WARNING, 73553202Sralph "rz%d%c: overlaps open partition (%c)\n", 73653202Sralph unit, part + 'a', i + 'a'); 73753202Sralph } 73853202Sralph } 73953202Sralph switch (mode) { 74053202Sralph case S_IFCHR: 74153202Sralph sc->sc_copenpart |= mask; 74253202Sralph break; 74353202Sralph case S_IFBLK: 74453202Sralph sc->sc_bopenpart |= mask; 74553202Sralph break; 74653202Sralph } 74753202Sralph sc->sc_openpart |= mask; 74852130Smckusick if (sc->sc_sd->sd_dk >= 0) 74952130Smckusick dk_wpms[sc->sc_sd->sd_dk] = sc->sc_wpms; 75052130Smckusick return (0); 75152130Smckusick } 75252130Smckusick 75353202Sralph rzclose(dev, flags, mode) 75452130Smckusick dev_t dev; 75553202Sralph int flags, mode; 75652130Smckusick { 75753202Sralph register struct rz_softc *sc = &rz_softc[rzunit(dev)]; 75853202Sralph u_long mask = (1 << rzpart(dev)); 75953202Sralph int s; 76053202Sralph 76153202Sralph switch (mode) { 76253202Sralph case S_IFCHR: 76353202Sralph sc->sc_copenpart &= ~mask; 76453202Sralph break; 76553202Sralph case S_IFBLK: 76653202Sralph sc->sc_bopenpart &= ~mask; 76753202Sralph break; 76853202Sralph } 76953202Sralph sc->sc_openpart = sc->sc_copenpart | sc->sc_bopenpart; 77053202Sralph 77153202Sralph /* 77253202Sralph * Should wait for I/O to complete on this partition even if 77353202Sralph * others are open, but wait for work on blkflush(). 77453202Sralph */ 77553202Sralph if (sc->sc_openpart == 0) { 77653202Sralph s = splbio(); 77753202Sralph while (sc->sc_tab.b_actf) 77853202Sralph sleep((caddr_t)&sc->sc_tab, PZERO - 1); 77953202Sralph splx(s); 78053202Sralph sc->sc_flags &= ~RZF_WLABEL; 78153202Sralph } 78252130Smckusick return (0); 78352130Smckusick } 78452130Smckusick 78552130Smckusick int 78652130Smckusick rzread(dev, uio) 78752130Smckusick dev_t dev; 78852130Smckusick struct uio *uio; 78952130Smckusick { 79052130Smckusick register struct rz_softc *sc = &rz_softc[rzunit(dev)]; 79152130Smckusick 79252130Smckusick if (sc->sc_format_pid && sc->sc_format_pid != curproc->p_pid) 79352130Smckusick return (EPERM); 79452130Smckusick 79552130Smckusick return (physio(rzstrategy, (struct buf *)0, dev, 79652130Smckusick B_READ, minphys, uio)); 79752130Smckusick } 79852130Smckusick 79952130Smckusick int 80052130Smckusick rzwrite(dev, uio) 80152130Smckusick dev_t dev; 80252130Smckusick struct uio *uio; 80352130Smckusick { 80452130Smckusick register struct rz_softc *sc = &rz_softc[rzunit(dev)]; 80552130Smckusick 80652130Smckusick if (sc->sc_format_pid && sc->sc_format_pid != curproc->p_pid) 80752130Smckusick return (EPERM); 80852130Smckusick 80952130Smckusick return (physio(rzstrategy, (struct buf *)0, dev, 81052130Smckusick B_WRITE, minphys, uio)); 81152130Smckusick } 81252130Smckusick 81352130Smckusick int 81452130Smckusick rzioctl(dev, cmd, data, flag, p) 81552130Smckusick dev_t dev; 81652130Smckusick int cmd; 81752130Smckusick caddr_t data; 81852130Smckusick int flag; 81952130Smckusick struct proc *p; 82052130Smckusick { 82152130Smckusick register struct rz_softc *sc = &rz_softc[rzunit(dev)]; 82253202Sralph int error; 82353202Sralph int flags; 82452130Smckusick 82552130Smckusick switch (cmd) { 82652130Smckusick default: 82752130Smckusick return (EINVAL); 82852130Smckusick 82952130Smckusick case SDIOCSFORMAT: 83052130Smckusick /* take this device into or out of "format" mode */ 83152130Smckusick if (suser(p->p_ucred, &p->p_acflag)) 83252130Smckusick return (EPERM); 83352130Smckusick 83452130Smckusick if (*(int *)data) { 83552130Smckusick if (sc->sc_format_pid) 83652130Smckusick return (EPERM); 83752130Smckusick sc->sc_format_pid = p->p_pid; 83852130Smckusick } else 83952130Smckusick sc->sc_format_pid = 0; 84052130Smckusick return (0); 84152130Smckusick 84252130Smckusick case SDIOCGFORMAT: 84352130Smckusick /* find out who has the device in format mode */ 84452130Smckusick *(int *)data = sc->sc_format_pid; 84552130Smckusick return (0); 84652130Smckusick 84752130Smckusick case SDIOCSCSICOMMAND: 84852130Smckusick /* 84952130Smckusick * Save what user gave us as SCSI cdb to use with next 85052130Smckusick * read or write to the char device. 85152130Smckusick */ 85252130Smckusick if (sc->sc_format_pid != p->p_pid) 85352130Smckusick return (EPERM); 85452130Smckusick if (legal_cmds[((struct scsi_fmt_cdb *)data)->cdb[0]] == 0) 85552130Smckusick return (EINVAL); 85652130Smckusick bcopy(data, (caddr_t)&sc->sc_cdb, sizeof(sc->sc_cdb)); 85752130Smckusick return (0); 85852130Smckusick 85952130Smckusick case SDIOCSENSE: 86052130Smckusick /* 86152130Smckusick * return the SCSI sense data saved after the last 86252130Smckusick * operation that completed with "check condition" status. 86352130Smckusick */ 86452130Smckusick bcopy((caddr_t)&sc->sc_sense, data, sizeof(sc->sc_sense)); 86552130Smckusick return (0); 86652130Smckusick 86753202Sralph case DIOCGDINFO: 86853202Sralph /* get the current disk label */ 86953202Sralph *(struct disklabel *)data = sc->sc_label; 87053202Sralph return (0); 87153202Sralph 87253202Sralph case DIOCSDINFO: 87353202Sralph /* set the current disk label */ 87453202Sralph if (!(flag & FWRITE)) 87553202Sralph return (EBADF); 87656629Sralph error = setdisklabel(&sc->sc_label, 87753202Sralph (struct disklabel *)data, 87856629Sralph (sc->sc_flags & RZF_WLABEL) ? 0 : sc->sc_openpart); 87956629Sralph return (error); 88053202Sralph 88153202Sralph case DIOCGPART: 88253202Sralph /* return the disk partition data */ 88353202Sralph ((struct partinfo *)data)->disklab = &sc->sc_label; 88453202Sralph ((struct partinfo *)data)->part = 88553202Sralph &sc->sc_label.d_partitions[rzpart(dev)]; 88653202Sralph return (0); 88753202Sralph 88853202Sralph case DIOCWLABEL: 88953202Sralph if (!(flag & FWRITE)) 89053202Sralph return (EBADF); 89153202Sralph if (*(int *)data) 89253202Sralph sc->sc_flags |= RZF_WLABEL; 89353202Sralph else 89453202Sralph sc->sc_flags &= ~RZF_WLABEL; 89553202Sralph return (0); 89653202Sralph 89753202Sralph case DIOCWDINFO: 89853202Sralph /* write the disk label to disk */ 89953202Sralph if (!(flag & FWRITE)) 90053202Sralph return (EBADF); 90153202Sralph error = setdisklabel(&sc->sc_label, 90253202Sralph (struct disklabel *)data, 90353202Sralph (sc->sc_flags & RZF_WLABEL) ? 0 : sc->sc_openpart); 90453202Sralph if (error) 90553202Sralph return (error); 90653202Sralph 90753202Sralph /* simulate opening partition 0 so write succeeds */ 90853202Sralph flags = sc->sc_flags; 90953202Sralph sc->sc_flags = RZF_ALIVE | RZF_WLABEL; 91053202Sralph error = writedisklabel(dev, rzstrategy, &sc->sc_label); 91153202Sralph sc->sc_flags = flags; 91253202Sralph return (error); 91352130Smckusick } 91452130Smckusick /*NOTREACHED*/ 91552130Smckusick } 91652130Smckusick 91752130Smckusick int 91852130Smckusick rzsize(dev) 91952130Smckusick dev_t dev; 92052130Smckusick { 92152130Smckusick register int unit = rzunit(dev); 92253202Sralph register int part = rzpart(dev); 92352130Smckusick register struct rz_softc *sc = &rz_softc[unit]; 92452130Smckusick 92564088Smckusick if (unit >= NRZ || !(sc->sc_flags & RZF_ALIVE)) 92652130Smckusick return (-1); 92752130Smckusick 92864088Smckusick /* 92964088Smckusick * We get called very early on (via swapconf) 93064088Smckusick * without the device being open so we need to 93164088Smckusick * read the disklabel here. 93264088Smckusick */ 93364088Smckusick if (!(sc->sc_flags & RZF_HAVELABEL)) 93464088Smckusick rzgetinfo(dev); 93564088Smckusick 93664088Smckusick if (part >= sc->sc_label.d_npartitions) 93764088Smckusick return (-1); 93853202Sralph return (sc->sc_label.d_partitions[part].p_size); 93952130Smckusick } 94052130Smckusick 94152130Smckusick /* 94252130Smckusick * Non-interrupt driven, non-dma dump routine. 94352130Smckusick */ 94452130Smckusick int 94552130Smckusick rzdump(dev) 94652130Smckusick dev_t dev; 94752130Smckusick { 94852130Smckusick #ifdef notdef 94952130Smckusick int part = rzpart(dev); 95052130Smckusick int unit = rzunit(dev); 95152130Smckusick register struct rz_softc *sc = &rz_softc[unit]; 95252130Smckusick register struct scsi_device *sd = sc->sc_hd; 95352130Smckusick register daddr_t baddr; 95452130Smckusick register int maddr; 95552130Smckusick register int pages, i; 95652130Smckusick int stat; 95752130Smckusick extern int lowram; 95852130Smckusick 95952130Smckusick /* 96052130Smckusick * Hmm... all vax drivers dump maxfree pages which is physmem minus 96152130Smckusick * the message buffer. Is there a reason for not dumping the 96252130Smckusick * message buffer? Savecore expects to read 'dumpsize' pages of 96352130Smckusick * dump, where dumpsys() sets dumpsize to physmem! 96452130Smckusick */ 96552130Smckusick pages = physmem; 96652130Smckusick 96752130Smckusick /* is drive ok? */ 96852130Smckusick if (unit >= NRZ || (sc->sc_flags & RZF_ALIVE) == 0) 96952130Smckusick return (ENXIO); 97052130Smckusick /* dump parameters in range? */ 97152130Smckusick if (dumplo < 0 || dumplo >= sc->sc_info.part[part].nblocks) 97252130Smckusick return (EINVAL); 97352130Smckusick if (dumplo + ctod(pages) > sc->sc_info.part[part].nblocks) 97452130Smckusick pages = dtoc(sc->sc_info.part[part].nblocks - dumplo); 97552130Smckusick maddr = lowram; 97652130Smckusick baddr = dumplo + sc->sc_info.part[part].strtblk; 97752130Smckusick /* scsi bus idle? */ 97852130Smckusick if (!scsireq(&sc->sc_dq)) { 97952130Smckusick scsireset(sd->sd_ctlr); 98052130Smckusick sc->sc_stats.rzresets++; 98152130Smckusick printf("[ drive %d reset ] ", unit); 98252130Smckusick } 98352130Smckusick for (i = 0; i < pages; i++) { 98452130Smckusick #define NPGMB (1024*1024/NBPG) 98552130Smckusick /* print out how many Mbs we have dumped */ 98652130Smckusick if (i && (i % NPGMB) == 0) 98752130Smckusick printf("%d ", i / NPGMB); 98852130Smckusick #undef NPBMG 98952130Smckusick mapin(mmap, (u_int)vmmap, btop(maddr), PG_URKR|PG_CI|PG_V); 99052130Smckusick stat = scsi_tt_write(sd->sd_ctlr, sd->sd_drive, sd->sd_slave, 99152130Smckusick vmmap, NBPG, baddr, sc->sc_bshift); 99252130Smckusick if (stat) { 99352130Smckusick printf("rzdump: scsi write error 0x%x\n", stat); 99452130Smckusick return (EIO); 99552130Smckusick } 99652130Smckusick maddr += NBPG; 99752130Smckusick baddr += ctod(1); 99852130Smckusick } 99952130Smckusick return (0); 100059823Sralph #else /* notdef */ 100152130Smckusick return (ENXIO); 100259823Sralph #endif /* notdef */ 100352130Smckusick } 100452130Smckusick #endif 1005