* Copyright (c) 1992 Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Van Jacobson of Lawrence Berkeley Laboratory and Ralph Campbell.
* %sccs.include.redist.c%
* @(#)rz.c 7.1 (Berkeley) %G%
* SCSI CCS (Command Command Set) disk driver.
* NOTE: The name was changed from "sd" to "rz" for DEC compatibility.
* I guess I can't avoid confusion someplace.
#include "devDiskLabel.h"
void rzstrategy(), rzstart(), rzdone();
struct driver rzdriver
= {
"rz", rzprobe
, rzstart
, rzdone
,
* Since the SCSI standard tends to hide the disk structure, we define
* partitions in terms of DEV_BSIZE blocks. The default partition table
* (for an unlabeled disk) reserves 512K for a boot area, has an 8 meg
* root and 32 meg of swap. The rest of the space on the drive goes in
* the G partition. As usual, the C partition covers the entire disk
* (including the boot area).
struct rzinfo rzdefaultpart
= {
1024, 17408, 16384 , /* A */
17408, 82944, 65536 , /* B */
17408, 115712, 98304 , /* D */
115712, 218112, 102400 , /* E */
struct scsi_device
*sc_sd
; /* physical unit info */
int sc_format_pid
; /* process using "format" mode */
short sc_flags
; /* see below */
short sc_type
; /* drive type from INQUIRY cmd */
u_int sc_blks
; /* number of blocks on device */
int sc_blksize
; /* device block size in bytes */
int sc_bshift
; /* convert device blocks to DEV_BSIZE */
u_int sc_wpms
; /* average xfer rate in 16bit wds/sec */
struct rzinfo sc_info
; /* drive partition table & label info */
struct rzstats sc_stats
; /* statisic counts */
struct buf sc_tab
; /* queue of pending operations */
struct buf sc_buf
; /* buf for doing I/O */
struct buf sc_errbuf
; /* buf for doing REQUEST_SENSE */
struct ScsiCmd sc_cmd
; /* command for controller */
ScsiGroup1Cmd sc_rwcmd
; /* SCSI cmd if not in "format" mode */
struct scsi_fmt_cdb sc_cdb
; /* SCSI cmd if in "format" mode */
struct scsi_fmt_sense sc_sense
; /* sense data from last cmd */
#define RZF_ALIVE 0x1 /* drive found and ready */
#define RZF_SENSEINPROGRESS 0x2 /* REQUEST_SENSE command in progress */
#define rzunit(x) ((minor(x) >> 3) & 0x7)
#define rzpart(x) (minor(x) & 0x7)
* Table of scsi commands users are allowed to access via "format" mode.
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,
* Test to see if device is present.
* Return true if found and initialized ok.
register struct scsi_device
*sd
;
register struct rz_softc
*sc
= &rz_softc
[sd
->sd_unit
];
/* init some parameters that don't change */
sc
->sc_cmd
.unit
= sd
->sd_unit
;
sc
->sc_rwcmd
.unitNumber
= sd
->sd_slave
;
/* try to find out what type of device this is */
sc
->sc_format_pid
= 1; /* force use of sc_cdb */
sc
->sc_cdb
.len
= sizeof(ScsiGroup0Cmd
);
scsiGroup0Cmd(SCSI_INQUIRY
, sd
->sd_slave
, 0, sizeof(inqbuf
),
(ScsiGroup0Cmd
*)sc
->sc_cdb
.cdb
);
sc
->sc_buf
.b_flags
= B_BUSY
| B_PHYS
| B_READ
;
sc
->sc_buf
.b_bcount
= sizeof(inqbuf
);
sc
->sc_buf
.b_un
.b_addr
= (caddr_t
)&inqbuf
;
sc
->sc_buf
.av_forw
= (struct buf
*)0;
sc
->sc_tab
.b_actf
= sc
->sc_tab
.b_actl
= &sc
->sc_buf
;
if (biowait(&sc
->sc_buf
) ||
(i
= sizeof(inqbuf
) - sc
->sc_buf
.b_resid
) < 5)
case SCSI_DISK_TYPE
: /* disk */
case SCSI_WORM_TYPE
: /* WORM */
case SCSI_ROM_TYPE
: /* CD-ROM */
case SCSI_OPTICAL_MEM_TYPE
: /* Magneto-optical */
default: /* not a disk */
sc
->sc_type
= inqbuf
.type
;
/* see if device is ready */
sc
->sc_cdb
.len
= sizeof(ScsiGroup0Cmd
);
scsiGroup0Cmd(SCSI_TEST_UNIT_READY
, sd
->sd_slave
, 0, 0,
(ScsiGroup0Cmd
*)sc
->sc_cdb
.cdb
);
sc
->sc_buf
.b_flags
= B_BUSY
| B_PHYS
| B_READ
;
sc
->sc_buf
.b_un
.b_addr
= (caddr_t
)0;
sc
->sc_buf
.av_forw
= (struct buf
*)0;
sc
->sc_tab
.b_actf
= sc
->sc_tab
.b_actl
= &sc
->sc_buf
;
sc
->sc_cmd
.cmd
= sc
->sc_cdb
.cdb
;
sc
->sc_cmd
.cmdlen
= sc
->sc_cdb
.len
;
sc
->sc_cmd
.buf
= (caddr_t
)0;
/* setup synchronous data transfers if the device supports it */
if (tries
== 10 && (inqbuf
.flags
& SCSI_SYNC
))
sc
->sc_cmd
.flags
= SCSICMD_USE_SYNC
;
(*sc
->sc_sd
->sd_cdriver
->d_start
)(&sc
->sc_cmd
);
if (!biowait(&sc
->sc_buf
))
if (!(sc
->sc_sense
.status
& SCSI_STATUS_CHECKCOND
))
sp
= (ScsiClass7Sense
*)sc
->sc_sense
.sense
;
if (sp
->key
== SCSI_CLASS7_UNIT_ATTN
&& tries
!= 9) {
/* drive recalibrating, give it a while */
if (sp
->key
== SCSI_CLASS7_NOT_READY
) {
/* try to spin-up disk with start/stop command */
sc
->sc_cdb
.len
= sizeof(ScsiGroup0Cmd
);
cp
= (ScsiStartStopCmd
*)sc
->sc_cdb
.cdb
;
cp
->command
= SCSI_START_STOP
;
cp
->unitNumber
= sd
->sd_slave
;
sc
->sc_buf
.b_flags
= B_BUSY
| B_PHYS
| B_READ
;
sc
->sc_buf
.b_un
.b_addr
= (caddr_t
)0;
sc
->sc_buf
.av_forw
= (struct buf
*)0;
sc
->sc_tab
.b_actf
= sc
->sc_tab
.b_actl
= &sc
->sc_buf
;
if (biowait(&sc
->sc_buf
))
/* find out how big a disk this is */
sc
->sc_cdb
.len
= sizeof(ScsiGroup1Cmd
);
scsiGroup1Cmd(SCSI_READ_CAPACITY
, sd
->sd_slave
, 0, 0,
(ScsiGroup1Cmd
*)sc
->sc_cdb
.cdb
);
sc
->sc_buf
.b_flags
= B_BUSY
| B_PHYS
| B_READ
;
sc
->sc_buf
.b_bcount
= sizeof(capbuf
);
sc
->sc_buf
.b_un
.b_addr
= (caddr_t
)capbuf
;
sc
->sc_buf
.av_forw
= (struct buf
*)0;
sc
->sc_tab
.b_actf
= sc
->sc_tab
.b_actl
= &sc
->sc_buf
;
if (biowait(&sc
->sc_buf
) || sc
->sc_buf
.b_resid
!= 0)
sc
->sc_blks
= (capbuf
[0] << 24) | (capbuf
[1] << 16) |
(capbuf
[2] << 8) | capbuf
[3];
sc
->sc_blksize
= (capbuf
[4] << 24) | (capbuf
[5] << 16) |
(capbuf
[6] << 8) | capbuf
[7];
printf("rz%d at %s%d drive %d slave %d", sd
->sd_unit
,
sd
->sd_cdriver
->d_name
, sd
->sd_ctlr
, sd
->sd_drive
,
if (inqbuf
.version
> 1 || i
< 36)
printf(" type 0x%x, qual 0x%x, ver %d",
inqbuf
.type
, inqbuf
.qualifier
, inqbuf
.version
);
char vid
[9], pid
[17], revl
[5];
bcopy((caddr_t
)inqbuf
.vendorID
, (caddr_t
)vid
, 8);
bcopy((caddr_t
)inqbuf
.productID
, (caddr_t
)pid
, 16);
bcopy((caddr_t
)inqbuf
.revLevel
, (caddr_t
)revl
, 4);
printf(" %s %s rev %s", vid
, pid
, revl
);
printf(", %d %d byte blocks\n", sc
->sc_blks
, sc
->sc_blksize
);
if (sc
->sc_blksize
!= DEV_BSIZE
) {
if (sc
->sc_blksize
< DEV_BSIZE
) {
printf("rz%d: need %d byte blocks - drive ignored\n",
for (i
= sc
->sc_blksize
; i
> DEV_BSIZE
; i
>>= 1)
sc
->sc_blks
<<= sc
->sc_bshift
;
sc
->sc_wpms
= 32 * (60 * DEV_BSIZE
/ 2); /* XXX */
sc
->sc_flags
= RZF_ALIVE
;
/* try to read disk label or partition table information */
if (rzreadlabel(sc
, sd
) == 0)
* We don't have a disk label, build a default partition
* table with 'standard' size root & swap and everything else
sc
->sc_info
= rzdefaultpart
;
sc
->sc_info
.part
[2].nblocks
= sc
->sc_blks
;
sc
->sc_info
.part
[2].endblk
= sc
->sc_blks
;
/* G gets from end of B to end of disk */
sc
->sc_info
.part
[6].nblocks
= sc
->sc_blks
- sc
->sc_info
.part
[1].endblk
;
sc
->sc_info
.part
[6].endblk
= sc
->sc_blks
;
* We also define the D, E and F paritions as an alternative to
* B and G. D is 48Mb, starts after A and is intended for swapping.
* E is 50Mb, starts after D and is intended for /usr. F starts
* after E and is what ever is left.
if (sc
->sc_blks
>= sc
->sc_info
.part
[4].endblk
) {
sc
->sc_info
.part
[5].nblocks
=
sc
->sc_blks
- sc
->sc_info
.part
[4].endblk
;
sc
->sc_info
.part
[5].endblk
= sc
->sc_blks
;
sc
->sc_info
.part
[5].strtblk
= 0;
sc
->sc_info
.part
[3] = sc
->sc_info
.part
[5];
sc
->sc_info
.part
[4] = sc
->sc_info
.part
[5];
* H is a single partition alternative to E and F.
if (sc
->sc_blks
>= sc
->sc_info
.part
[3].endblk
) {
sc
->sc_info
.part
[7].nblocks
=
sc
->sc_blks
- sc
->sc_info
.part
[3].endblk
;
sc
->sc_info
.part
[7].endblk
= sc
->sc_blks
;
sc
->sc_info
.part
[7].strtblk
= 0;
/* doesn't exist or not a CCS device */
* Try to read the disk label and fill in the partition table info.
register struct rz_softc
*sc
;
register struct scsi_device
*sd
;
register struct size
*sp
;
Sun_DiskLabel
*sunLabelPtr
;
Dec_DiskLabel
*decLabelPtr
;
char labelBuffer
[DEV_BSIZE
];
* The label of a SCSI disk normally resides in the first sector.
* Format and send a SCSI READ command to fetch the sector.
sc
->sc_buf
.b_flags
= B_BUSY
| B_PHYS
| B_READ
;
sc
->sc_buf
.b_bcount
= sizeof(labelBuffer
);
sc
->sc_buf
.b_un
.b_addr
= labelBuffer
;
sc
->sc_buf
.b_cylin
= SUN_LABEL_SECTOR
;
sc
->sc_buf
.av_forw
= (struct buf
*)0;
sc
->sc_tab
.b_actf
= sc
->sc_tab
.b_actl
= &sc
->sc_buf
;
if (error
= biowait(&sc
->sc_buf
))
sunLabelPtr
= (Sun_DiskLabel
*)labelBuffer
;
if (sunLabelPtr
->magic
== SUN_DISK_MAGIC
) {
* XXX - Should really check if label is valid.
if (rzdebug
& RZB_PRLABEL
) {
printf("rz%d: SUN label %s\n", sd
->sd_unit
,
sunLabelPtr
->asciiLabel
);
for (part
= 0; part
< DEV_NUM_DISK_PARTS
; part
++, sp
++) {
sunLabelPtr
->map
[part
].cylinder
*
sunLabelPtr
->map
[part
].numBlocks
;
sp
->endblk
= sp
->strtblk
+ sp
->nblocks
;
if (rzdebug
& RZB_PRLABEL
)
printf(" (%d,%d)", sp
->strtblk
, sp
->nblocks
);
if (rzdebug
& RZB_PRLABEL
)
* The disk isn't in SUN or UNIX format so try Dec format.
* We have to read the right sector first.
sc
->sc_buf
.b_flags
= B_BUSY
| B_PHYS
| B_READ
;
sc
->sc_buf
.b_bcount
= sizeof(labelBuffer
);
sc
->sc_buf
.b_un
.b_addr
= labelBuffer
;
sc
->sc_buf
.b_cylin
= DEC_LABEL_SECTOR
;
sc
->sc_buf
.av_forw
= (struct buf
*)0;
sc
->sc_tab
.b_actf
= sc
->sc_tab
.b_actl
= &sc
->sc_buf
;
if (error
= biowait(&sc
->sc_buf
))
decLabelPtr
= (Dec_DiskLabel
*)labelBuffer
;
if (decLabelPtr
->magic
== DEC_LABEL_MAGIC
&&
decLabelPtr
->isPartitioned
) {
* XXX - Should really check if label is valid.
if (rzdebug
& RZB_PRLABEL
) {
printf("rz%d: DEC label\n", sd
->sd_unit
);
for (part
= 0; part
< DEV_NUM_DISK_PARTS
; part
++, sp
++) {
sp
->strtblk
= decLabelPtr
->map
[part
].startBlock
;
sp
->nblocks
= decLabelPtr
->map
[part
].numBlocks
;
sp
->endblk
= sp
->strtblk
+ sp
->nblocks
;
if (rzdebug
& RZB_PRLABEL
)
printf(" (%d,%d)", sp
->strtblk
, sp
->nblocks
);
if (rzdebug
& RZB_PRLABEL
)
* 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
register struct buf
*cbp
;
cbp
= (struct buf
*)malloc(sizeof(struct buf
), M_DEVBUF
, M_WAITOK
);
cbuf
= (caddr_t
)malloc(bsize
, M_DEVBUF
, M_WAITOK
);
bzero((caddr_t
)cbp
, sizeof(*cbp
));
if (rzdebug
& RZB_PARTIAL
)
printf("rzlblkstrat: bp %x flags %x bn %x resid %x addr %x\n",
bp
, bp
->b_flags
, bn
, resid
, addr
);
register int boff
= dbtob(bn
) & (bsize
- 1);
if (boff
|| resid
< bsize
) {
rz_softc
[rzunit(bp
->b_dev
)].sc_stats
.rzpartials
++;
count
= MIN(resid
, bsize
- boff
);
cbp
->b_flags
= B_BUSY
| B_PHYS
| B_READ
;
cbp
->b_blkno
= bn
- btodb(boff
);
if (rzdebug
& RZB_PARTIAL
)
printf(" readahead: bn %x cnt %x off %x addr %x\n",
cbp
->b_blkno
, count
, boff
, addr
);
if (cbp
->b_flags
& B_ERROR
) {
bp
->b_error
= cbp
->b_error
;
if (bp
->b_flags
& B_READ
) {
bcopy(&cbuf
[boff
], addr
, count
);
bcopy(addr
, &cbuf
[boff
], count
);
if (rzdebug
& RZB_PARTIAL
)
printf(" writeback: bn %x cnt %x off %x addr %x\n",
cbp
->b_blkno
, count
, boff
, addr
);
count
= resid
& ~(bsize
- 1);
if (rzdebug
& RZB_PARTIAL
)
printf(" fulltrans: bn %x cnt %x addr %x\n",
cbp
->b_blkno
, count
, addr
);
cbp
->b_flags
= B_BUSY
| B_PHYS
| (bp
->b_flags
& B_READ
);
if (cbp
->b_flags
& B_ERROR
) {
bp
->b_error
= cbp
->b_error
;
if (rzdebug
& RZB_PARTIAL
)
printf(" done: bn %x resid %x addr %x\n",
register int unit
= rzunit(bp
->b_dev
);
register int part
= rzpart(bp
->b_dev
);
register struct rz_softc
*sc
= &rz_softc
[unit
];
if (sc
->sc_format_pid
!= curproc
->p_pid
) {
sz
= (bp
->b_bcount
+ (DEV_BSIZE
- 1)) >> DEV_BSHIFT
;
if (bn
< 0 || bn
+ sz
> sc
->sc_info
.part
[part
].nblocks
) {
if (bn
== sc
->sc_info
.part
[part
].nblocks
) {
bp
->b_resid
= bp
->b_bcount
;
* Non-aligned or partial-block transfers handled specially.
if ((dbtob(bn
) & s
) || (bp
->b_bcount
& s
)) {
rzlblkstrat(bp
, sc
->sc_blksize
);
bp
->b_cylin
= (bn
+ sc
->sc_info
.part
[part
].strtblk
) >>
/* don't let disksort() see sc_errbuf */
while (sc
->sc_flags
& RZF_SENSEINPROGRESS
)
printf("SENSE\n"); /* XXX */
disksort(&sc
->sc_tab
, bp
);
if (sc
->sc_tab
.b_active
== 0) {
register struct rz_softc
*sc
= &rz_softc
[unit
];
register struct buf
*bp
= sc
->sc_tab
.b_actf
;
sc
->sc_cmd
.buf
= bp
->b_un
.b_addr
;
sc
->sc_cmd
.buflen
= bp
->b_bcount
;
if (sc
->sc_format_pid
|| (sc
->sc_flags
& RZF_SENSEINPROGRESS
)) {
sc
->sc_cmd
.flags
= !(bp
->b_flags
& B_READ
) ?
SCSICMD_DATA_TO_DEVICE
: 0;
sc
->sc_cmd
.cmd
= sc
->sc_cdb
.cdb
;
sc
->sc_cmd
.cmdlen
= sc
->sc_cdb
.len
;
if (bp
->b_flags
& B_READ
) {
sc
->sc_rwcmd
.command
= SCSI_READ_EXT
;
sc
->sc_cmd
.flags
= SCSICMD_DATA_TO_DEVICE
;
sc
->sc_rwcmd
.command
= SCSI_WRITE_EXT
;
sc
->sc_cmd
.cmd
= (u_char
*)&sc
->sc_rwcmd
;
sc
->sc_cmd
.cmdlen
= sizeof(sc
->sc_rwcmd
);
sc
->sc_rwcmd
.highAddr
= n
>> 24;
sc
->sc_rwcmd
.midHighAddr
= n
>> 16;
sc
->sc_rwcmd
.midLowAddr
= n
>> 8;
sc
->sc_rwcmd
.lowAddr
= n
;
n
= howmany(bp
->b_bcount
, sc
->sc_blksize
);
sc
->sc_rwcmd
.highBlockCount
= n
>> 8;
sc
->sc_rwcmd
.lowBlockCount
= n
;
if ((bp
->b_bcount
& (sc
->sc_blksize
- 1)) != 0)
printf("rz%d: partial block xfer -- %x bytes\n",
sc
->sc_stats
.rztransfers
++;
if ((n
= sc
->sc_sd
->sd_dk
) >= 0) {
dk_wds
[n
] += bp
->b_bcount
>> 6;
/* tell controller to start this command */
(*sc
->sc_sd
->sd_cdriver
->d_start
)(&sc
->sc_cmd
);
* This is called by the controller driver when the command is done.
rzdone(unit
, error
, resid
, status
)
int error
; /* error number from errno.h */
int resid
; /* amount not transfered */
int status
; /* SCSI status byte */
register struct rz_softc
*sc
= &rz_softc
[unit
];
register struct buf
*bp
= sc
->sc_tab
.b_actf
;
register struct scsi_device
*sd
= sc
->sc_sd
;
printf("rz%d: bp == NULL\n", unit
);
dk_busy
&= ~(1 << sd
->sd_dk
);
if (sc
->sc_flags
& RZF_SENSEINPROGRESS
) {
sc
->sc_flags
&= ~RZF_SENSEINPROGRESS
;
sc
->sc_tab
.b_actf
= bp
= bp
->av_forw
; /* remove sc_errbuf */
if (error
|| (status
& SCSI_STATUS_CHECKCOND
)) {
printf("rz%d: error reading sense data: error %d scsi status 0x%x\n",
* We got an error during the REQUEST_SENSE,
* fill in no sense for data.
sc
->sc_sense
.sense
[0] = 0x70;
sc
->sc_sense
.sense
[2] = SCSI_CLASS7_NO_SENSE
;
scsiPrintSense((ScsiClass7Sense
*)sc
->sc_sense
.sense
,
sizeof(sc
->sc_sense
.sense
) - resid
);
} else if (error
|| (status
& SCSI_STATUS_CHECKCOND
)) {
printf("rz%d: error %d scsi status 0x%x\n",
sc
->sc_sense
.status
= status
;
if (status
& SCSI_STATUS_CHECKCOND
) {
* Start a REQUEST_SENSE command.
* Since we are called at interrupt time, we can't
* wait for the command to finish; that's why we use
sc
->sc_flags
|= RZF_SENSEINPROGRESS
;
sc
->sc_cdb
.len
= sizeof(ScsiGroup0Cmd
);
scsiGroup0Cmd(SCSI_REQUEST_SENSE
, sd
->sd_slave
, 0,
sizeof(sc
->sc_sense
.sense
),
(ScsiGroup0Cmd
*)sc
->sc_cdb
.cdb
);
sc
->sc_errbuf
.b_flags
= B_BUSY
| B_PHYS
| B_READ
;
sc
->sc_errbuf
.b_bcount
= sizeof(sc
->sc_sense
.sense
);
sc
->sc_errbuf
.b_un
.b_addr
= (caddr_t
)sc
->sc_sense
.sense
;
sc
->sc_errbuf
.av_forw
= bp
;
sc
->sc_tab
.b_actf
= &sc
->sc_errbuf
;
sc
->sc_sense
.status
= status
;
sc
->sc_tab
.b_actf
= bp
->av_forw
;
rzopen(dev
, flags
, mode
, p
)
register int unit
= rzunit(dev
);
register struct rz_softc
*sc
= &rz_softc
[unit
];
if (!(sc
->sc_flags
& RZF_ALIVE
) || suser(p
->p_ucred
, &p
->p_acflag
))
if (sc
->sc_sd
->sd_dk
>= 0)
dk_wpms
[sc
->sc_sd
->sd_dk
] = sc
->sc_wpms
;
register struct rz_softc
*sc
= &rz_softc
[rzunit(dev
)];
if (sc
->sc_format_pid
&& sc
->sc_format_pid
!= curproc
->p_pid
)
return (physio(rzstrategy
, (struct buf
*)0, dev
,
register struct rz_softc
*sc
= &rz_softc
[rzunit(dev
)];
if (sc
->sc_format_pid
&& sc
->sc_format_pid
!= curproc
->p_pid
)
return (physio(rzstrategy
, (struct buf
*)0, dev
,
rzioctl(dev
, cmd
, data
, flag
, p
)
register struct rz_softc
*sc
= &rz_softc
[rzunit(dev
)];
/* take this device into or out of "format" mode */
if (suser(p
->p_ucred
, &p
->p_acflag
))
sc
->sc_format_pid
= p
->p_pid
;
/* find out who has the device in format mode */
*(int *)data
= sc
->sc_format_pid
;
* Save what user gave us as SCSI cdb to use with next
* read or write to the char device.
if (sc
->sc_format_pid
!= p
->p_pid
)
if (legal_cmds
[((struct scsi_fmt_cdb
*)data
)->cdb
[0]] == 0)
bcopy(data
, (caddr_t
)&sc
->sc_cdb
, sizeof(sc
->sc_cdb
));
* return the SCSI sense data saved after the last
* operation that completed with "check condition" status.
bcopy((caddr_t
)&sc
->sc_sense
, data
, sizeof(sc
->sc_sense
));
register int unit
= rzunit(dev
);
register struct rz_softc
*sc
= &rz_softc
[unit
];
if (unit
>= NRZ
|| !(sc
->sc_flags
& RZF_ALIVE
))
return (sc
->sc_info
.part
[rzpart(dev
)].nblocks
);
* Non-interrupt driven, non-dma dump routine.
register struct rz_softc
*sc
= &rz_softc
[unit
];
register struct scsi_device
*sd
= sc
->sc_hd
;
* Hmm... all vax drivers dump maxfree pages which is physmem minus
* the message buffer. Is there a reason for not dumping the
* message buffer? Savecore expects to read 'dumpsize' pages of
* dump, where dumpsys() sets dumpsize to physmem!
if (unit
>= NRZ
|| (sc
->sc_flags
& RZF_ALIVE
) == 0)
/* dump parameters in range? */
if (dumplo
< 0 || dumplo
>= sc
->sc_info
.part
[part
].nblocks
)
if (dumplo
+ ctod(pages
) > sc
->sc_info
.part
[part
].nblocks
)
pages
= dtoc(sc
->sc_info
.part
[part
].nblocks
- dumplo
);
baddr
= dumplo
+ sc
->sc_info
.part
[part
].strtblk
;
if (!scsireq(&sc
->sc_dq
)) {
printf("[ drive %d reset ] ", unit
);
for (i
= 0; i
< pages
; i
++) {
#define NPGMB (1024*1024/NBPG)
/* print out how many Mbs we have dumped */
if (i
&& (i
% NPGMB
) == 0)
printf("%d ", i
/ NPGMB
);
mapin(mmap
, (u_int
)vmmap
, btop(maddr
), PG_URKR
|PG_CI
|PG_V
);
stat
= scsi_tt_write(sd
->sd_ctlr
, sd
->sd_drive
, sd
->sd_slave
,
vmmap
, NBPG
, baddr
, sc
->sc_bshift
);
printf("rzdump: scsi write error 0x%x\n", stat
);