2650 lines
65 KiB
C
2650 lines
65 KiB
C
/* @(#)sf.c 1.1 92/07/30 SMI */
|
|
|
|
/*
|
|
* Copyright (c) 1988 by Sun Microsystems, Inc.
|
|
*/
|
|
#include "sf.h"
|
|
#if NSF > 0
|
|
|
|
#define SFDEBUG 1 /* Allow compiling of debug code */
|
|
#define REL4 /* enable release 4.00 mods */
|
|
|
|
/*
|
|
* SCSI driver for SCSI disks.
|
|
*/
|
|
#ifndef REL4
|
|
#include "sf.h"
|
|
#include "../h/param.h"
|
|
#include "../h/systm.h"
|
|
#include "../h/dk.h"
|
|
#include "../h/buf.h"
|
|
#include "../h/conf.h"
|
|
#include "../h/dir.h"
|
|
#include "../h/user.h"
|
|
#include "../h/map.h"
|
|
#include "../h/vmmac.h"
|
|
#include "../h/ioctl.h"
|
|
#include "../h/uio.h"
|
|
#include "../h/kernel.h"
|
|
#include "../h/dkbad.h"
|
|
#include "../h/fcntl.h"
|
|
#include "../h/file.h"
|
|
#include "../h/proc.h"
|
|
|
|
#include "../machine/pte.h"
|
|
#include "../machine/psl.h"
|
|
#include "../machine/mmu.h"
|
|
#include "../machine/cpu.h"
|
|
|
|
#include "../sun/dklabel.h"
|
|
#include "../sun/dkio.h"
|
|
|
|
#include "../sundev/mbvar.h"
|
|
#include "../sundev/screg.h"
|
|
#include "../sundev/sireg.h"
|
|
#include "../sundev/scsi.h"
|
|
#include "../sundev/sfreg.h"
|
|
|
|
#else REL4
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/dk.h>
|
|
#include <sys/buf.h>
|
|
#include <sys/conf.h>
|
|
#include <sys/user.h>
|
|
#include <sys/map.h>
|
|
#include <sys/vmmac.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/uio.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/dkbad.h>
|
|
#include <sys/fcntl.h>
|
|
#include <sys/file.h>
|
|
|
|
#include <machine/pte.h>
|
|
#include <machine/psl.h>
|
|
#include <machine/mmu.h>
|
|
#include <machine/cpu.h>
|
|
|
|
#include <sun/dklabel.h>
|
|
#include <sun/dkio.h>
|
|
|
|
#include <sundev/mbvar.h>
|
|
#include <sundev/screg.h>
|
|
#include <sundev/sireg.h>
|
|
#include <sundev/scsi.h>
|
|
#include <sundev/sfreg.h>
|
|
#endif REL4
|
|
|
|
#if defined(REL4) && defined(SF_FORMAT)
|
|
#include <vm/faultcode.h>
|
|
#include <vm/hat.h>
|
|
#include <vm/seg.h>
|
|
#include <vm/as.h>
|
|
|
|
#endif defined(REL4) && defined(SF_FORMAT)
|
|
|
|
|
|
#define SFDTYPE(flags) ((flags & 0xff00) >> 8)
|
|
/* #define MAX_RETRIES 4 /* retry limit */
|
|
#define MAX_RETRIES 1 /* retry limit */
|
|
/* #define MAX_RESTORES 4 /* rezero unit limit (after retries) */
|
|
#define MAX_RESTORES 1 /* rezero unit limit (after retries) */
|
|
#define MAX_FAILS 20 /* soft errors before reassign */
|
|
#define MAX_LABEL_RETRIES 1
|
|
#define MAX_LABEL_RESTORES 1
|
|
#define MAX_BUSY 10
|
|
#define EL_RETRY 1 /* Error msg threshold, retries */
|
|
#define EL_REST 0 /* Error msg threshold, restores */
|
|
#define EL_FAILS 10 /* Error msg threshold, soft errors */
|
|
|
|
|
|
#define LPART(dev) (dev & (NLPART -1))
|
|
#define SFUNIT(dev) ((dev >> 3) & (NUNIT -1))
|
|
#define SFNUM(un) (un - sfunits)
|
|
|
|
|
|
#ifdef SFDEBUG
|
|
short sf_debug = 0; /*
|
|
* 0 = normal operation
|
|
* 1 = extended error info only
|
|
* 2 = debug and error info
|
|
* 3 = all status info
|
|
*/
|
|
/* Handy debugging 0, 1, and 2 argument printfs */
|
|
#define SF_PRINT_CMD(un) \
|
|
if (sf_debug > 1) sf_print_cmd(un)
|
|
#define DPRINTF(str) \
|
|
if (sf_debug > 1) printf(str)
|
|
#define DPRINTF1(str, arg1) \
|
|
if (sf_debug > 1) printf(str,arg1)
|
|
#define DPRINTF2(str, arg1, arg2) \
|
|
if (sf_debug > 1) printf(str,arg1,arg2)
|
|
|
|
/* Handy extended error reporting 0, 1, and 2 argument printfs */
|
|
#define EPRINTF(str) \
|
|
if (sf_debug) printf(str)
|
|
#define EPRINTF1(str, arg1) \
|
|
if (sf_debug) printf(str,arg1)
|
|
#define EPRINTF2(str, arg1, arg2) \
|
|
if (sf_debug) printf(str,arg1,arg2)
|
|
#define DEBUG_DELAY(cnt) \
|
|
if (sf_debug) DELAY(cnt)
|
|
|
|
#else SFDEBUG
|
|
#define SF_PRINT_CMD(un)
|
|
#define DPRINTF(str)
|
|
#define DPRINTF1(str, arg2)
|
|
#define DPRINTF2(str, arg1, arg2)
|
|
#define EPRINTF(str)
|
|
#define EPRINTF1(str, arg2)
|
|
#define EPRINTF2(str, arg1, arg2)
|
|
#define DEBUG_DELAY(cnt)
|
|
#endif SFDEBUG
|
|
|
|
extern char *strncpy();
|
|
|
|
extern struct scsi_unit sfunits[];
|
|
extern struct scsi_unit_subr scsi_unit_subr[];
|
|
extern struct scsi_floppy sfdisk[];
|
|
extern int nsfdisk;
|
|
extern int scsi_debug;
|
|
short sf_retry = 1; /*
|
|
/* short sf_retry = EL_RETRY; /*
|
|
* Error message threshold, retries.
|
|
* Make it global so manufacturing can
|
|
* override setting.
|
|
*/
|
|
|
|
#ifdef SFDEBUG
|
|
sf_print_buffer(y, count)
|
|
register u_char *y;
|
|
register int count;
|
|
{
|
|
register int x;
|
|
|
|
for (x = 0; x < count; x++)
|
|
printf("%x ", *y++);
|
|
printf("\n");
|
|
}
|
|
#endif SFDEBUG
|
|
|
|
|
|
/*
|
|
* Return a pointer to this unit's unit structure.
|
|
*/
|
|
sfunitptr(md)
|
|
register struct mb_device *md;
|
|
{
|
|
return ((int)&sfunits[md->md_unit]);
|
|
}
|
|
|
|
|
|
static
|
|
sftimer(dev)
|
|
register dev_t dev;
|
|
{
|
|
register struct scsi_floppy *dsi;
|
|
register struct scsi_unit *un;
|
|
register struct scsi_ctlr *c;
|
|
register u_int unit;
|
|
|
|
unit = SFUNIT(dev);
|
|
un = &sfunits[unit];
|
|
dsi = &sfdisk[unit];
|
|
c = un->un_c;
|
|
|
|
/* DPRINTF("sftimer:\n"); */
|
|
if (dsi->un_openf >= OPENING) {
|
|
#ifdef SF_TIMEOUT
|
|
if ((dsi->un_timeout != 0) && (--dsi->un_timeout == 0)) {
|
|
|
|
/* Process command timeout for normal I/O operations */
|
|
printf("sf%d: sftimer: I/O request timeout\n", unit);
|
|
if ((*c->c_ss->scs_deque)(c, un)) {
|
|
/* Can't Find CDB I/O request to kill, help! */
|
|
printf("sf%d: sftimer: can't abort request\n",
|
|
unit);
|
|
(*un->un_c->c_ss->scs_reset)(un->un_c, 0);
|
|
}
|
|
} else
|
|
if (dsi->un_timeout != 0) {
|
|
/* DPRINTF2("sftimer: running, open= %d, timeout= %d\n",
|
|
dsi->un_openf, dsi->un_timeout); */
|
|
}
|
|
#endif SF_TIMEOUT
|
|
|
|
/* Process opening delay timeout */
|
|
} else if ((dsi->un_timeout != 0) && (--dsi->un_timeout == 0)) {
|
|
DPRINTF("sftimer: running...\n");
|
|
wakeup((caddr_t)dev);
|
|
}
|
|
timeout(sftimer, (caddr_t)dev, 30*hz);
|
|
}
|
|
|
|
|
|
/*
|
|
* Attach device (boot time).
|
|
*/
|
|
sfattach(md)
|
|
register struct mb_device *md;
|
|
{
|
|
register struct scsi_unit *un;
|
|
register struct scsi_floppy *dsi;
|
|
struct scsi_inquiry_data *sid;
|
|
int i;
|
|
|
|
dsi = &sfdisk[md->md_unit];
|
|
un = &sfunits[md->md_unit];
|
|
|
|
/*
|
|
* link in, fill in unit struct.
|
|
*/
|
|
un->un_md = md;
|
|
un->un_mc = md->md_mc;
|
|
un->un_unit = md->md_unit;
|
|
un->un_target = TARGET(md->md_slave);
|
|
un->un_lun = LUN(md->md_slave);
|
|
un->un_ss = &scsi_unit_subr[TYPE(md->md_flags)];
|
|
un->un_present = 0;
|
|
|
|
dsi->un_openf = OPENING;
|
|
dsi->un_flags = 0;
|
|
dsi->un_timeout = 0;
|
|
dsi->un_timer = 0;
|
|
dsi->un_status = 0;
|
|
dsi->un_retries = 0;
|
|
dsi->un_restores = 0;
|
|
dsi->un_sec_left = 0;
|
|
dsi->un_total_errors = 0;
|
|
dsi->un_err_resid = 0;
|
|
dsi->un_err_blkno = 0;
|
|
dsi->un_cyl_start = 0;
|
|
dsi->un_cyl_end = 0;
|
|
dsi->un_cylin_last = 0;
|
|
dsi->un_lp1 = NULL;
|
|
dsi->un_lp2 = NULL;
|
|
dsi->un_ctype = CTYPE_UNKNOWN;
|
|
dsi->sf_spt = 0;
|
|
dsi->sf_mdb = 0;
|
|
dsi->sf_nhead = 0;
|
|
dsi->sf_nblk = 0;
|
|
dsi->sf_rate = 0xfa;
|
|
switch (SFDTYPE(md->md_flags)) {
|
|
default:
|
|
case 0:
|
|
dsi->sf_mdb = 0x1e;
|
|
break;
|
|
case 1:
|
|
dsi->sf_mdb = 0x16;
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Set default disk geometry and partition table.
|
|
* This is necessary so we can later open the device
|
|
* if we don't find it at probe time.
|
|
*/
|
|
bzero((caddr_t)&(dsi->un_g), sizeof (struct dk_geom));
|
|
bzero((caddr_t)dsi->un_map, sizeof (struct dk_allmap));
|
|
dsi->un_g.dkg_ncyl = 78;
|
|
dsi->un_g.dkg_acyl = 0;
|
|
dsi->un_g.dkg_pcyl = 80;
|
|
dsi->un_g.dkg_nhead = 2;
|
|
dsi->un_g.dkg_nsect = 9;
|
|
dsi->un_cyl_size = 9;
|
|
|
|
/*
|
|
* Allocate space for request sense/inquiry buffer in
|
|
* Multibus memory. Align it to a longword boundary.
|
|
*/
|
|
sid = (struct scsi_inquiry_data *)rmalloc(iopbmap,
|
|
(long)(sizeof (struct scsi_inquiry_data) + 4));
|
|
if (sid == NULL) {
|
|
printf("sf%d: sfattach: no space for inquiry data\n",
|
|
SFNUM(un));
|
|
return;
|
|
}
|
|
|
|
while ((u_int)sid & 0x03)
|
|
((u_int)sid)++;
|
|
dsi->un_sense = (int)sid;
|
|
|
|
#ifdef notdef
|
|
EPRINTF2("sf%d: sfattach: buffer= 0x%x, ", SFNUM(un), (int)sid);
|
|
EPRINTF2("dsi= 0x%x, un= 0x%x\n", dsi, un);
|
|
DPRINTF2("sfattach: looking for lun %d on target %d\n",
|
|
LUN(md->md_slave), TARGET(md->md_slave));
|
|
|
|
#endif
|
|
/*
|
|
* Test for unit ready. The first test checks
|
|
* for a non-existant device. The other tests
|
|
* wait for the drive to get ready.
|
|
*/
|
|
if (simple(un, SC_TEST_UNIT_READY, 0, 0, 0) > 1) {
|
|
DPRINTF("sfattach: unit offline\n");
|
|
return;
|
|
}
|
|
for (i = 0; i < MAX_BUSY; i++) {
|
|
if (simple(un, SC_TEST_UNIT_READY, 0, 0, 0) == 0) {
|
|
goto SFATTACH_UNIT;
|
|
|
|
} else if (un->un_scb.chk) {
|
|
goto SFATTACH_UNIT;
|
|
|
|
} else if (un->un_scb.busy && !un->un_scb.is) {
|
|
EPRINTF("sfattach: unit busy\n");
|
|
DELAY(4000000); /* Wait 4 Sec. */
|
|
|
|
} else if (un->un_scb.is) {
|
|
EPRINTF("sfattach: reservation conflict\n");
|
|
break;
|
|
}
|
|
}
|
|
DPRINTF("sfattach: unit offline\n");
|
|
return;
|
|
|
|
SFATTACH_UNIT:
|
|
if (simple(un, SC_TEST_UNIT_READY, 0, 0, 0) != 0) {
|
|
DPRINTF("sfattach: unit failed\n");
|
|
return;
|
|
}
|
|
|
|
bzero((caddr_t)sid, (u_int)sizeof (struct scsi_inquiry_data));
|
|
if (simple(un, SC_INQUIRY, (char *) sid - DVMA, 0,
|
|
(int)sizeof (struct scsi_inquiry_data)) == 0) {
|
|
/* Only CCS controllers support Inquiry command */
|
|
#ifdef SFDEBUG
|
|
/* if (sf_debug > 2)
|
|
sf_print_buffer((u_char *)sid, 32); */
|
|
#endif SFDEBUG
|
|
if (bcmp(sid->vid, "NCR HC F", 8) == 0) {
|
|
EPRINTF("sfattach: NCR floppy controller found\n");
|
|
dsi->un_ctype = CTYPE_NCRFLOP;
|
|
dsi->un_flags = 0; /* dis/reconnect turn on */
|
|
} else {
|
|
EPRINTF("sfattach: CCS found\n");
|
|
dsi->un_ctype = CTYPE_CCS;
|
|
dsi->un_flags = 0;
|
|
}
|
|
} else {
|
|
EPRINTF("sfattach: unknow conntroller type\n");
|
|
dsi->un_ctype = CTYPE_UNKNOWN;
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* Read the label from the disk.
|
|
* Return true if read was ok, false otherwise.
|
|
*/
|
|
static
|
|
getlabel(un, l, dev)
|
|
register struct scsi_unit *un;
|
|
register struct fk_label *l;
|
|
dev_t dev;
|
|
{
|
|
register int s;
|
|
register struct scsi_floppy *sfp;
|
|
int err;
|
|
struct ms_med_parms {
|
|
struct ccs_modesel_head_fl header;
|
|
struct ccs_modesel_medium page5;
|
|
} *ms_med_parms, *oms_med_parms;
|
|
|
|
|
|
sfp = &sfdisk[un->un_unit];
|
|
/*
|
|
* SET DISK MEDIUM PARAMETERS (PAGE 5)
|
|
*/
|
|
ms_med_parms = (struct ms_med_parms *)rmalloc(iopbmap,
|
|
(long)(sizeof (struct ms_med_parms) + 4));
|
|
oms_med_parms = ms_med_parms;
|
|
while ((u_int)ms_med_parms & 0x03)
|
|
((u_int)ms_med_parms)++;
|
|
bzero((char *)ms_med_parms, sizeof (struct ms_med_parms));
|
|
/* First get them */
|
|
if (sfcmd(dev, SC_MODE_SENSE, 0x5,
|
|
sizeof (struct ms_med_parms),
|
|
(caddr_t)ms_med_parms, 0)) {
|
|
EPRINTF("Can not get characteristics\n");
|
|
return (ENXIO);
|
|
}
|
|
|
|
/* set page5 stuff */
|
|
sfp->sf_rate = 0xfa;
|
|
sfp->sf_spt = 9;
|
|
ms_med_parms->header.medium = sfp->sf_mdb;
|
|
ms_med_parms->page5.xfer_rate = sfp->sf_rate;
|
|
ms_med_parms->page5.data_bytes = 512;
|
|
ms_med_parms->page5.nhead = 2;
|
|
ms_med_parms->page5.sec_trk = 9;
|
|
ms_med_parms->page5.ncyl = 0x50;
|
|
ms_med_parms->page5.ssn = 1;
|
|
s = splr(pritospl(un->un_mc->mc_intpri));
|
|
if (sfcmd(dev, SC_MODE_SELECT, 0x5,
|
|
sizeof (struct ms_med_parms),
|
|
(caddr_t)ms_med_parms, 0)) {
|
|
EPRINTF("Can not set characteristics\n");
|
|
rmfree(iopbmap, (long)(sizeof (struct ms_med_parms) + 4),
|
|
(u_long)oms_med_parms);
|
|
(void) splx(s);
|
|
return (ENXIO);
|
|
}
|
|
err = sfcmd(dev, SC_READ_LABEL, 1, 1, (caddr_t)l, 0);
|
|
if (err == 0) {
|
|
rmfree(iopbmap, (long)(sizeof (struct ms_med_parms) + 4),
|
|
(u_long)oms_med_parms);
|
|
(void) splx(s);
|
|
return (1);
|
|
}
|
|
/* the stupid floppy could be high density so switch and try again */
|
|
if (sfp->sf_mdb == 0x1e) {
|
|
sfp->sf_rate = 0x1f4;
|
|
sfp->sf_spt = 18;
|
|
} else {
|
|
sfp->sf_mdb = 0x1a;
|
|
sfp->sf_rate = 0x1f4;
|
|
sfp->sf_spt = 15;
|
|
}
|
|
ms_med_parms->page5.xfer_rate = sfp->sf_rate;
|
|
ms_med_parms->page5.sec_trk = sfp->sf_spt;
|
|
if (sfcmd(dev, SC_MODE_SELECT, 0x5,
|
|
sizeof (struct ms_med_parms),
|
|
(caddr_t)ms_med_parms, 0)) {
|
|
EPRINTF("Can not set characteristics\n");
|
|
sfp->sf_rate = 0xfa;
|
|
rmfree(iopbmap, (long)(sizeof (struct ms_med_parms) + 4),
|
|
(u_long)oms_med_parms);
|
|
(void) splx(s);
|
|
return (ENXIO);
|
|
}
|
|
err = sfcmd(dev, SC_READ_LABEL, 1, 1, (caddr_t)l, 0);
|
|
if (err == 0) {
|
|
rmfree(iopbmap, (long)(sizeof (struct ms_med_parms) + 4),
|
|
(u_long)oms_med_parms);
|
|
(void) splx(s);
|
|
return (1);
|
|
}
|
|
(void) sfcmd(dev, SC_REZERO_UNIT, 0, 0, (caddr_t)0, 0);
|
|
sfp->sf_rate = 0xfa;
|
|
sfp->sf_spt = 9;
|
|
if (sfp->sf_mdb == 0x1a)
|
|
sfp->sf_mdb = 16;
|
|
rmfree(iopbmap, (long)(sizeof (struct ms_med_parms) + 4),
|
|
(u_long)oms_med_parms);
|
|
(void) splx(s);
|
|
return (0);
|
|
}
|
|
|
|
static
|
|
uselabel(un, l, dev)
|
|
register struct scsi_unit *un;
|
|
register struct fk_label *l;
|
|
dev_t dev;
|
|
{
|
|
register struct scsi_floppy *sfp;
|
|
struct ms_med_parms {
|
|
struct ccs_modesel_head_fl header;
|
|
struct ccs_modesel_medium page5;
|
|
} *ms_med_parms, *oms_med_parms;
|
|
|
|
|
|
un->un_present = 1; /* "it's here..." */
|
|
sfp = &sfdisk[un->un_unit];
|
|
/* set default geometry */
|
|
sfp->sf_spt = 9;
|
|
sfp->sf_nhead = 2;
|
|
sfp->sf_nblk = 720 * 2;
|
|
sfp->sf_xrate = 0xfa;
|
|
sfp->sf_bsec = 512;
|
|
sfp->sf_step = 1;
|
|
sfp->un_g.dkg_ncyl = sfp->sf_nblk;
|
|
sfp->un_g.dkg_acyl = 0;
|
|
sfp->un_g.dkg_bcyl = 0;
|
|
sfp->un_g.dkg_nhead = sfp->sf_nhead;
|
|
sfp->un_g.dkg_bhead = 0;
|
|
sfp->un_g.dkg_nsect = sfp->sf_spt;
|
|
sfp->un_g.dkg_gap1 = 0;
|
|
sfp->un_g.dkg_gap2 = 0;
|
|
sfp->un_g.dkg_intrlv =0;
|
|
sfp->un_g.dkg_pcyl = 0;
|
|
/*
|
|
* Old labels don't have pcyl in them, so we make a guess at it.
|
|
*/
|
|
if (sfp->un_g.dkg_pcyl == 0)
|
|
sfp->un_g.dkg_pcyl = sfp->un_g.dkg_ncyl + sfp->un_g.dkg_acyl;
|
|
sfp->un_cyl_size = sfp->un_g.dkg_nhead * sfp->un_g.dkg_nsect;
|
|
|
|
/*
|
|
* Fill in partition table.
|
|
*/
|
|
/* default to three partitions for now */
|
|
sfp->un_map[0].dkl_cylno = 0;
|
|
sfp->un_map[0].dkl_nblk = 8;
|
|
sfp->un_map[2].dkl_cylno = 0;
|
|
sfp->un_map[2].dkl_nblk = sfp->sf_nblk;
|
|
sfp->un_map[6].dkl_cylno = 1;
|
|
sfp->un_map[6].dkl_nblk = sfp->sf_nblk - 8;
|
|
sfp = &sfdisk[un->un_unit];
|
|
/*
|
|
* Check magic number of the label
|
|
*/
|
|
if ((l->fkl_magich != FKL_MAGIC) || (l->fkl_magicl != FKL_MAGIC) ) {
|
|
return (0);
|
|
}
|
|
|
|
switch (l->fkl_type) {
|
|
case DSHSPT:
|
|
if (sfp->sf_rate == 0xfa) {
|
|
sfp->sf_spt = 9;
|
|
sfp->sf_nblk = 1440;
|
|
sfp->sf_xrate = 0xfa;
|
|
} else {
|
|
sfp->sf_spt = 18;
|
|
sfp->sf_nblk = 2880;
|
|
sfp->sf_xrate = 0x1f4;
|
|
}
|
|
sfp->sf_nhead = 2;
|
|
sfp->sf_bsec = 512;
|
|
sfp->sf_step = 1;
|
|
break;
|
|
|
|
case SS8SPT:
|
|
sfp->sf_spt = 8;
|
|
sfp->sf_nhead = 1;
|
|
sfp->sf_nblk = 640;
|
|
sfp->sf_xrate = 0xfa;
|
|
sfp->sf_bsec = 512;
|
|
sfp->sf_step = 1;
|
|
break;
|
|
|
|
case DS8SPT:
|
|
sfp->sf_spt = 8;
|
|
sfp->sf_nhead = 2;
|
|
sfp->sf_nblk = 640 * 2;
|
|
sfp->sf_xrate = 0xfa;
|
|
sfp->sf_bsec = 512;
|
|
sfp->sf_step = 1;
|
|
break;
|
|
|
|
case SS9SPT:
|
|
sfp->sf_spt = 9;
|
|
sfp->sf_nhead = 1;
|
|
sfp->sf_nblk = 720;
|
|
sfp->sf_xrate = 0xfa;
|
|
sfp->sf_bsec = 512;
|
|
sfp->sf_step = 1;
|
|
break;
|
|
|
|
case DS9SPT:
|
|
sfp->sf_spt = 9;
|
|
sfp->sf_nhead = 2;
|
|
sfp->sf_nblk = 720 * 2;
|
|
sfp->sf_xrate = 0xfa;
|
|
sfp->sf_bsec = 512;
|
|
sfp->sf_step = 1;
|
|
break;
|
|
|
|
default:
|
|
sfp->sf_spt = 9;
|
|
sfp->sf_nhead = 2;
|
|
sfp->sf_nblk = 720 * 2;
|
|
sfp->sf_xrate = 0xfa;
|
|
sfp->sf_bsec = 512;
|
|
sfp->sf_step = 1;
|
|
EPRINTF2("sf%d: unknown label %x\n", un->un_unit, sfp->sf_mdb);
|
|
break;
|
|
|
|
}
|
|
/*
|
|
* Fill in disk geometry from label.
|
|
*/
|
|
un->un_present = 1; /* "it's here..." */
|
|
sfp->un_g.dkg_ncyl = sfp->sf_nblk;
|
|
sfp->un_g.dkg_acyl = 0;
|
|
sfp->un_g.dkg_bcyl = 0;
|
|
sfp->un_g.dkg_nhead = sfp->sf_nhead;
|
|
sfp->un_g.dkg_bhead = 0;
|
|
sfp->un_g.dkg_nsect = sfp->sf_spt;
|
|
sfp->un_g.dkg_gap1 = 0;
|
|
sfp->un_g.dkg_gap2 = 0;
|
|
sfp->un_g.dkg_intrlv =0;
|
|
sfp->un_g.dkg_pcyl = 0;
|
|
/*
|
|
* Old labels don't have pcyl in them, so we make a guess at it.
|
|
*/
|
|
if (sfp->un_g.dkg_pcyl == 0)
|
|
sfp->un_g.dkg_pcyl = sfp->un_g.dkg_ncyl + sfp->un_g.dkg_acyl;
|
|
sfp->un_cyl_size = sfp->un_g.dkg_nhead * sfp->un_g.dkg_nsect;
|
|
|
|
/*
|
|
* Fill in partition table.
|
|
*/
|
|
/* default to three partitions for now */
|
|
sfp->un_map[0].dkl_cylno = 0;
|
|
sfp->un_map[0].dkl_nblk = 8;
|
|
sfp->un_map[2].dkl_cylno = 0;
|
|
sfp->un_map[2].dkl_nblk = sfp->sf_nblk;
|
|
sfp->un_map[6].dkl_cylno = 1;
|
|
sfp->un_map[6].dkl_nblk = sfp->sf_nblk - 8;
|
|
/*
|
|
* SET DISK MEDIUM PARAMETERS (PAGE 5)
|
|
*/
|
|
ms_med_parms = (struct ms_med_parms *)rmalloc(iopbmap,
|
|
(long)(sizeof (struct ms_med_parms) + 4));
|
|
oms_med_parms = ms_med_parms;
|
|
while ((u_int)ms_med_parms & 0x03)
|
|
((u_int)ms_med_parms)++;
|
|
bzero((char *)ms_med_parms, sizeof (struct ms_med_parms));
|
|
/* First get them */
|
|
if (sfcmd(dev, SC_MODE_SENSE, 0x5,
|
|
sizeof (struct ms_med_parms),
|
|
(caddr_t)ms_med_parms, 0)) {
|
|
EPRINTF("Can not get characteristics\n");
|
|
return (ENXIO);
|
|
}
|
|
|
|
|
|
|
|
/* set page5 stuff */
|
|
ms_med_parms->header.medium = sfp->sf_mdb;
|
|
ms_med_parms->page5.xfer_rate = sfp->sf_rate;
|
|
ms_med_parms->page5.nhead = sfp->sf_nhead;
|
|
ms_med_parms->page5.sec_trk = sfp->sf_spt;
|
|
ms_med_parms->page5.data_bytes = 512;
|
|
ms_med_parms->page5.ncyl = 0x50;
|
|
|
|
if (sfcmd(dev, SC_MODE_SELECT, 0x5,
|
|
sizeof (struct ms_med_parms),
|
|
(caddr_t)ms_med_parms, 0)) {
|
|
EPRINTF("Can not set characteristics\n");
|
|
rmfree(iopbmap, (long)(sizeof (struct ms_med_parms) + 4),
|
|
(u_long)oms_med_parms);
|
|
return (ENXIO);
|
|
}
|
|
rmfree(iopbmap, (long)(sizeof (struct ms_med_parms) + 4),
|
|
(u_long)oms_med_parms);
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Run a command in polled mode.
|
|
* Return true if successful, false otherwise.
|
|
*/
|
|
static
|
|
simple(un, cmd, dma_addr, secno, nsect)
|
|
register struct scsi_unit *un;
|
|
register int cmd, secno, nsect, dma_addr;
|
|
{
|
|
register struct scsi_cdb *cdb;
|
|
register struct scsi_ctlr *c;
|
|
register int err;
|
|
|
|
/*
|
|
* Grab and clear the command block.
|
|
*/
|
|
c = un->un_c;
|
|
cdb = &un->un_cdb;
|
|
bzero((caddr_t)cdb, CDB_GROUP0);
|
|
|
|
/*
|
|
* Plug in command block values.
|
|
*/
|
|
cdb->cmd = cmd;
|
|
if (SCSI_RECV_DATA_CMD(cmd))
|
|
un->un_flags |= SC_UNF_RECV_DATA;
|
|
else
|
|
un->un_flags &= ~SC_UNF_RECV_DATA;
|
|
|
|
c->c_un = un;
|
|
cdb->lun = un->un_lun;
|
|
FORMG0ADDR(cdb, secno);
|
|
FORMG0COUNT(cdb, nsect);
|
|
un->un_dma_addr = dma_addr;
|
|
if (cmd == SC_INQUIRY)
|
|
un->un_dma_count = nsect;
|
|
else
|
|
un->un_dma_count = nsect << SECDIV;
|
|
|
|
/*
|
|
* Fire up the pup.
|
|
*/
|
|
if (err = (*c->c_ss->scs_cmd)(c, un, 0)) {
|
|
if (err > 1) {
|
|
return (2); /* Hard failure */
|
|
} else {
|
|
return (1); /* Recoverable failure */
|
|
}
|
|
}
|
|
return (0); /* No failure */
|
|
}
|
|
|
|
|
|
/*
|
|
* This routine opens a disk. Note that we can handle disks
|
|
* that make an appearance after boot time.
|
|
*/
|
|
/*ARGSUSED*/
|
|
sfopen(dev, flag)
|
|
dev_t dev;
|
|
int flag;
|
|
{
|
|
register struct scsi_unit *un;
|
|
register struct fk_label *l;
|
|
register struct dk_map *lp;
|
|
register int unit;
|
|
register struct scsi_floppy *dsi;
|
|
register struct scsi_inquiry_data *sid;
|
|
struct fk_label *old_l;
|
|
|
|
unit = SFUNIT(dev);
|
|
if (unit >= nsfdisk) {
|
|
EPRINTF("sfopen: illegal unit\n");
|
|
return (ENXIO);
|
|
}
|
|
|
|
un = &sfunits[unit];
|
|
dsi = &sfdisk[unit];
|
|
if (un->un_mc == 0) {
|
|
EPRINTF("sfopen: disk not atached\n");
|
|
return (ENXIO);
|
|
}
|
|
|
|
/*
|
|
* If command timeouts not activated yet, switch it on.
|
|
*/
|
|
#ifdef SF_TIMEOUT
|
|
if (dsi->un_timer == 0) {
|
|
EPRINTF("sfopen: starting timer\n");
|
|
dsi->un_timer++;
|
|
timeout(sftimer, (caddr_t)dev, 30*hz);
|
|
}
|
|
#endif SF_TIMEOUT
|
|
|
|
/*
|
|
* Check for special opening mode.
|
|
*/
|
|
EPRINTF("sfopen: opening device\n");
|
|
lp = &dsi->un_map[LPART(dev)];
|
|
lp->dkl_nblk = 1536;
|
|
|
|
dsi->un_openf = OPENING;
|
|
dsi->un_flags = SC_UNF_NO_DISCON; /* no disconnects */
|
|
if (sfcmd(dev, SC_TEST_UNIT_READY, 0, 0, (caddr_t)0, 0) &&
|
|
dsi->un_openf == CLOSED) {
|
|
EPRINTF("sfopen: not ready\n");
|
|
dsi->un_timer = 0;
|
|
untimeout(sftimer, (caddr_t)dev);
|
|
return (ENXIO);
|
|
}
|
|
|
|
dsi->un_openf = OPENING;
|
|
(void) sfcmd(dev, SC_TEST_UNIT_READY, 0, 0, (caddr_t)0, 0);
|
|
dsi->un_openf = OPENING;
|
|
if (sfcmd(dev, SC_TEST_UNIT_READY, 0, 0, (caddr_t)0, 0)) {
|
|
EPRINTF("sfopen: not ready\n");
|
|
dsi->un_timer = 0;
|
|
untimeout(sftimer, (caddr_t)dev);
|
|
return (ENXIO);
|
|
}
|
|
dsi->un_openf = OPENING;
|
|
sid = (struct scsi_inquiry_data *)dsi->un_sense;
|
|
bzero((caddr_t)sid, (u_int)sizeof (struct scsi_inquiry_data));
|
|
if (sfcmd(dev, SC_INQUIRY, 0,
|
|
sizeof (struct scsi_inquiry_data), (caddr_t)sid, 0)) {
|
|
EPRINTF("sfopen: unknown controller type\n");
|
|
dsi->un_ctype = CTYPE_UNKNOWN;
|
|
return (ENXIO);
|
|
} else {
|
|
#ifdef SFDEBUG
|
|
/* if (sf_debug > 2)
|
|
sf_print_buffer((u_char *)sid, 32); */
|
|
#endif SFDEBUG
|
|
dsi->un_flags = 0;
|
|
if (bcmp(sid->vid, "NCR HC F", 8) == 0) {
|
|
/* EPRINTF("sfopen: NCR floppy controller found\n"); */
|
|
dsi->un_ctype = CTYPE_NCRFLOP;
|
|
} else {
|
|
EPRINTF("sfopen: CCS found\n");
|
|
dsi->un_ctype = CTYPE_CCS;
|
|
}
|
|
}
|
|
|
|
|
|
/* Allocate space for label on longword boundary */
|
|
old_l = l =
|
|
(struct fk_label *)rmalloc(iopbmap, (long)(SECSIZE +4));
|
|
if (l == NULL) {
|
|
printf("sf%d: no space for disk label\n", SFNUM(un));
|
|
return (ENXIO);
|
|
}
|
|
while ((u_int)l & 0x03)
|
|
((u_int)l)++;
|
|
|
|
DPRINTF("sfopen: reading label\n");
|
|
dsi->un_openf = OPEN;
|
|
dsi->un_restores = 1/* MAX_RESTORES */;
|
|
if (getlabel(un, l, dev)) {
|
|
if (uselabel(un, l, dev)) {
|
|
rmfree(iopbmap, (long)(SECSIZE + 4), (u_long)old_l);
|
|
if (flag & O_NDELAY) {
|
|
EPRINTF("sfopen: suppressing label error\n");
|
|
return (0);
|
|
}
|
|
return (0);
|
|
}
|
|
rmfree(iopbmap, (long)(SECSIZE + 4), (u_long)old_l);
|
|
return (0);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Dummy close routine
|
|
*/
|
|
|
|
/*ARGSUSED*/
|
|
sfclose(dev,flag)
|
|
dev_t dev;
|
|
int flag;
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* This routine returns the size of a logical partition. It is called
|
|
* from the device switch at normal priority.
|
|
*/
|
|
sfsize(dev)
|
|
register dev_t dev;
|
|
{
|
|
register struct scsi_unit *un;
|
|
register struct dk_map *lp;
|
|
register struct scsi_floppy *dsi;
|
|
|
|
if (SFUNIT(dev) >= nsfdisk) {
|
|
EPRINTF("sfsize: illegal unit\n");
|
|
return (-1);
|
|
}
|
|
un = &sfunits[SFUNIT(dev)];
|
|
/* DPRINTF("sfsize:\n"); */
|
|
|
|
if (un->un_present) {
|
|
/* DPRINTF("sfsize: getting info\n"); */
|
|
dsi = &sfdisk[SFUNIT(dev)];
|
|
lp = &dsi->un_map[LPART(dev)];
|
|
return (lp->dkl_nblk);
|
|
} else {
|
|
/* EPRINTF("sfsize: unit not present\n"); */
|
|
return (-1);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* This routine is the focal point of internal commands to the controller.
|
|
* NOTE: this routine assumes that all operations done before the disk's
|
|
* geometry is defined.
|
|
*/
|
|
sfcmd(dev, cmd, block, count, addr, options)
|
|
dev_t dev;
|
|
u_int cmd, block, count;
|
|
caddr_t addr;
|
|
int options;
|
|
{
|
|
register struct scsi_floppy *dsi;
|
|
register struct scsi_unit *un;
|
|
register struct buf *bp;
|
|
int s;
|
|
long b_flags;
|
|
|
|
un = &sfunits[SFUNIT(dev)];
|
|
dsi = &sfdisk[SFUNIT(dev)];
|
|
bp = &un->un_sbuf;
|
|
|
|
/* DPRINTF("sfcmd:\n"); */
|
|
/* s = splr(pritospl(un->un_mc->mc_intpri)); */
|
|
s = splr(pritospl(3));
|
|
while (bp->b_flags & B_BUSY) {
|
|
bp->b_flags |= B_WANTED;
|
|
/* DPRINTF1("sfcmd: sleeping..., bp= 0x%x\n", bp); */
|
|
(void) sleep((caddr_t) bp, PRIBIO);
|
|
}
|
|
|
|
bp->b_flags = B_BUSY | B_READ;
|
|
(void) splx(s);
|
|
/* DPRINTF1("sfcmd: waking..., bp= 0x%x\n", bp); */
|
|
/* DPRINTF1("sfcmd: waking up with addr=0x%x\n", addr); */
|
|
|
|
un->un_scmd = cmd;
|
|
bp->b_dev = dev;
|
|
bp->b_bcount = count;
|
|
bp->b_blkno = block;
|
|
bp->b_un.b_addr = addr;
|
|
dsi->un_options = options;
|
|
|
|
#ifdef SF_FORMAT
|
|
if (options & (SD_DVMA_RD | SD_DVMA_WR)) {
|
|
/* DPRINTF2("sfcmd: addr= 0x%x size= 0x%x\n", addr, count); */
|
|
bp->b_flags |= B_PHYS;
|
|
bp->b_proc = u.u_procp;
|
|
u.u_procp->p_flag |= SPHYSIO;
|
|
/*
|
|
* Fault lock the address range of the buffer.
|
|
*/
|
|
if (as_fault(u.u_procp->p_as, bp->b_un.b_addr,
|
|
(u_int)count, F_SOFTLOCK,
|
|
(options & SD_DVMA_WR) ? S_WRITE : S_READ)) {
|
|
|
|
EPRINTF("sfcmd: as_fault error1\n");
|
|
b_flags = bp->b_flags = B_ERROR;
|
|
goto SFCMD_EXIT;
|
|
}
|
|
}
|
|
#endif SF_FORMAT
|
|
/*
|
|
* Execute the I/O request.
|
|
*/
|
|
sfstrategy(bp);
|
|
(void) iowait(bp);
|
|
|
|
#ifdef SF_FORMAT
|
|
/*
|
|
* Release memory and DVMA resources.
|
|
*/
|
|
if (options & (SD_DVMA_RD | SD_DVMA_WR)) {
|
|
if (as_fault(u.u_procp->p_as, bp->b_un.b_addr,
|
|
(u_int)bp->b_bcount, F_SOFTUNLOCK,
|
|
(options & SD_DVMA_WR) ? S_WRITE : S_READ)) {
|
|
|
|
EPRINTF("sfcmd: as_fault error2\n");
|
|
b_flags = bp->b_flags = B_ERROR;
|
|
goto SFCMD_EXIT;
|
|
}
|
|
s = splr(pritospl(3));
|
|
/* s = splr(pritospl(un->un_mc->mc_intpri));*/
|
|
u.u_procp->p_flag &= ~SPHYSIO;
|
|
bp->b_flags &= ~(B_BUSY | B_PHYS);
|
|
(void) splx(s);
|
|
}
|
|
|
|
SFCMD_EXIT:
|
|
#endif SF_FORMAT
|
|
|
|
bp->b_flags &= ~B_BUSY;
|
|
b_flags = bp->b_flags;
|
|
if (bp->b_flags & B_WANTED) {
|
|
/* DPRINTF1("sfcmd: waking..., bp= 0x%x\n", bp); */
|
|
wakeup((caddr_t)bp);
|
|
}
|
|
return (b_flags & B_ERROR);
|
|
}
|
|
|
|
|
|
/*
|
|
* This routine is the high level interface to the disk. It performs
|
|
* reads and writes on the disk using the buf as the method of communication.
|
|
* It is called from the device switch for block operations and via physio()
|
|
* for raw operations. It is called at normal priority.
|
|
*/
|
|
sfstrategy(bp)
|
|
register struct buf *bp;
|
|
{
|
|
register struct scsi_unit *un;
|
|
register struct mb_device *md;
|
|
register struct dk_map *lp;
|
|
register u_int bn, cyl;
|
|
register struct diskhd *dh;
|
|
register struct scsi_floppy *dsi;
|
|
register int s;
|
|
int unit;
|
|
|
|
/* DPRINTF("sfstrategy:\n"); */
|
|
unit = dkunit(bp);
|
|
if (unit >= nsfdisk) {
|
|
EPRINTF("sfstrategy: invalid unit\n");
|
|
bp->b_flags |= B_ERROR;
|
|
iodone(bp);
|
|
return;
|
|
}
|
|
un = &sfunits[unit];
|
|
md = un->un_md;
|
|
dsi = &sfdisk[unit];
|
|
lp = &dsi->un_map[LPART(bp->b_dev)];/* which partition */
|
|
bn = bp->b_blkno;
|
|
|
|
if (bp != &un->un_sbuf) {
|
|
if ((un->un_present == 0) || (lp->dkl_nblk == 0)) {
|
|
EPRINTF("sfstrategy: unit not present\n");
|
|
EPRINTF2("sfstrategy: bn= 0x%x nblk= 0x%x\n",
|
|
bn, lp->dkl_nblk);
|
|
bp->b_flags |= B_ERROR;
|
|
iodone(bp);
|
|
return;
|
|
}
|
|
/* Check for EOM */
|
|
if (un->un_present && (bn >= lp->dkl_nblk)) {
|
|
EPRINTF("sfstrategy: invalid block addr\n");
|
|
bp->b_resid = bp->b_bcount;
|
|
iodone(bp);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ((bn >= dsi->un_cyl_start) && (bn < dsi->un_cyl_end) &&
|
|
( (int)lp == dsi->un_lp1)) {
|
|
/* DPRINTF("WIN "); */
|
|
bp->b_cylin = dsi->un_cylin_last;
|
|
|
|
} else {
|
|
/* DPRINTF("LOSE\n"); */
|
|
dsi->un_lp1 = (int)lp;
|
|
cyl = bn / dsi->un_cyl_size;
|
|
|
|
dsi->un_cyl_start = cyl * dsi->un_cyl_size;
|
|
dsi->un_cyl_end = dsi->un_cyl_start + dsi->un_cyl_size;
|
|
|
|
cyl += lp->dkl_cylno + dsi->un_g.dkg_bcyl;
|
|
bp->b_cylin = dsi->un_cylin_last = cyl;
|
|
}
|
|
s = splr(pritospl(un->un_mc->mc_intpri));
|
|
dh = &md->md_utab;
|
|
disksort(dh, bp);
|
|
|
|
/* call unit start routine to queue up device, if it
|
|
* currently isn't queued. Does not actually start command
|
|
*/
|
|
(*un->un_c->c_ss->scs_ustart)(un);
|
|
|
|
/* call start routine to run the next SCSI command */
|
|
/* Now we start the command */
|
|
(*un->un_c->c_ss->scs_start)(un);
|
|
(void) splx(s);
|
|
}
|
|
|
|
|
|
/*
|
|
* Set up a transfer for the controller
|
|
*/
|
|
sfstart(bp, un)
|
|
register struct buf *bp;
|
|
register struct scsi_unit *un;
|
|
{
|
|
register struct dk_map *lp;
|
|
register struct scsi_floppy *dsi;
|
|
register int nblk;
|
|
|
|
/* DPRINTF("sfstart:\n"); */
|
|
|
|
dsi = &sfdisk[dkunit(bp)];
|
|
lp = &dsi->un_map[LPART(bp->b_dev)];
|
|
|
|
/* Process internal I/O requests */
|
|
if (bp == &un->un_sbuf) {
|
|
/* DPRINTF("sfstart: internal I/O\n"); */
|
|
un->un_cmd = un->un_scmd;
|
|
un->un_count = bp->b_bcount;
|
|
un->un_blkno = bp->b_blkno;
|
|
un->un_flags = 0;
|
|
if (dsi->un_options & (SD_DVMA_RD | SD_DVMA_WR))
|
|
un->un_flags = SC_UNF_SPECIAL_DVMA;
|
|
return (1);
|
|
}
|
|
|
|
/* Process file system I/O requests */
|
|
if (bp->b_flags & B_READ) {
|
|
/* DPRINTF("sfstart: read\n"); */
|
|
un->un_cmd = SC_READ;
|
|
} else {
|
|
/* DPRINTF("sfstart: write\n"); */
|
|
un->un_cmd = SC_WRITE;
|
|
}
|
|
|
|
/* Compute absolute block location */
|
|
if ((int)lp == dsi->un_lp2) {
|
|
un->un_blkno = bp->b_blkno + dsi->un_last_cyl_size;
|
|
} else {
|
|
dsi->un_lp2 = (int)lp;
|
|
dsi->un_last_cyl_size = lp->dkl_cylno * dsi->un_cyl_size;
|
|
un->un_blkno = bp->b_blkno + dsi->un_last_cyl_size;
|
|
}
|
|
|
|
/* Finish processing read/write request */
|
|
nblk = (bp->b_bcount + (SECSIZE - 1)) >> SECDIV;
|
|
un->un_count = MIN(nblk, (lp->dkl_nblk - bp->b_blkno));
|
|
un->un_flags = SC_UNF_DVMA;
|
|
return (1);
|
|
}
|
|
|
|
|
|
/*
|
|
* Make a cdb for disk I/O.
|
|
*/
|
|
sfmkcdb(un)
|
|
struct scsi_unit *un;
|
|
{
|
|
register struct scsi_cdb *cdb;
|
|
register struct scsi_floppy *dsi;
|
|
|
|
/* DPRINTF("sfmkcdb:\n"); */
|
|
|
|
dsi = &sfdisk[un->un_unit];
|
|
cdb = &un->un_cdb;
|
|
bzero((caddr_t)cdb, CDB_GROUP0);
|
|
cdb->cmd = un->un_cmd;
|
|
cdb->lun = un->un_lun;
|
|
|
|
switch (un->un_cmd) {
|
|
case SC_READ:
|
|
/* DPRINTF("sfmkcdb: read\n"); */
|
|
dsi->un_timeout = 4;
|
|
un->un_flags |= (SC_UNF_RECV_DATA | dsi->un_flags);
|
|
FORMG0ADDR(cdb, un->un_blkno);
|
|
FORMG0COUNT(cdb, un->un_count);
|
|
un->un_dma_addr = un->un_baddr;
|
|
un->un_dma_count = un->un_count << SECDIV;
|
|
break;
|
|
|
|
case SC_WRITE:
|
|
/* DPRINTF("sfmkcdb: write\n"); */
|
|
dsi->un_timeout = 4;
|
|
un->un_flags = (un->un_flags & ~SC_UNF_RECV_DATA) |
|
|
dsi->un_flags;
|
|
FORMG0ADDR(cdb, un->un_blkno);
|
|
FORMG0COUNT(cdb, un->un_count);
|
|
un->un_dma_addr = un->un_baddr;
|
|
un->un_dma_count = un->un_count << SECDIV;
|
|
break;
|
|
|
|
case SC_WRITE_VERIFY:
|
|
/* DPRINTF("sfmkcdb: write verify\n"); */
|
|
dsi->un_timeout = 4;
|
|
un->un_flags = (un->un_flags & ~SC_UNF_RECV_DATA) |
|
|
dsi->un_flags;
|
|
FORMG1ADDR(cdb, un->un_blkno);
|
|
FORMG1COUNT(cdb, un->un_count);
|
|
un->un_dma_addr = un->un_baddr;
|
|
un->un_dma_count = un->un_count << SECDIV;
|
|
break;
|
|
|
|
case SC_REQUEST_SENSE:
|
|
DPRINTF("sfmkcdb: request sense\n");
|
|
dsi->un_timeout = 4;
|
|
un->un_flags |= (SC_UNF_RECV_DATA | dsi->un_flags);
|
|
FORMG0COUNT(cdb, sizeof (struct scsi_sense));
|
|
un->un_dma_addr = (int)dsi->un_sense - (int)DVMA;
|
|
un->un_dma_count = sizeof (struct scsi_sense);
|
|
bzero((caddr_t)(dsi->un_sense), sizeof (struct scsi_sense));
|
|
return;
|
|
|
|
case SC_SPECIAL_READ:
|
|
/* DPRINTF1("sfmkcdb: special read blkno= 0x%x\n", un->un_blkno); */
|
|
dsi->un_timeout = 4;
|
|
un->un_cmd = cdb->cmd = SC_READ;
|
|
un->un_flags |= (SC_UNF_RECV_DATA | dsi->un_flags);
|
|
FORMG0ADDR(cdb, un->un_blkno);
|
|
FORMG0COUNT(cdb, un->un_count >> SECDIV);
|
|
un->un_dma_addr = un->un_baddr;
|
|
un->un_dma_count = un->un_count;
|
|
break;
|
|
|
|
case SC_SPECIAL_WRITE:
|
|
/* DPRINTF1("sfmkcdb: special write blkno= 0x%x\n", un->un_blkno); */
|
|
dsi->un_timeout = 4;
|
|
un->un_cmd = cdb->cmd = SC_WRITE;
|
|
un->un_flags = (un->un_flags & ~SC_UNF_RECV_DATA) |
|
|
dsi->un_flags;
|
|
FORMG0ADDR(cdb, un->un_blkno);
|
|
FORMG0COUNT(cdb, un->un_count >> SECDIV);
|
|
un->un_dma_addr = un->un_baddr;
|
|
un->un_dma_count = un->un_count;
|
|
break;
|
|
|
|
case SC_READ_LABEL:
|
|
DPRINTF("sfmkcdb: read label\n");
|
|
dsi->un_timeout = 4;
|
|
un->un_flags |= (SC_UNF_RECV_DATA | dsi->un_flags);
|
|
un->un_cmd = cdb->cmd = SC_READ;
|
|
FORMG0ADDR(cdb, un->un_blkno);
|
|
FORMG0COUNT(cdb, 1);
|
|
un->un_dma_addr = (int)un->un_sbuf.b_un.b_addr - (int)DVMA;
|
|
un->un_dma_count = SECSIZE;
|
|
break;
|
|
|
|
case SC_REZERO_UNIT:
|
|
EPRINTF("sfmkcdb: rezero unit\n");
|
|
dsi->un_timeout = 4;
|
|
un->un_flags = (un->un_flags & ~SC_UNF_RECV_DATA) |
|
|
dsi->un_flags;
|
|
un->un_dma_addr = 0;
|
|
un->un_dma_count = 0;
|
|
return;
|
|
|
|
case SC_TEST_UNIT_READY:
|
|
/* DPRINTF("sfmkcdb: test unit ready\n"); */
|
|
dsi->un_timeout = 2;
|
|
un->un_flags = (un->un_flags & ~SC_UNF_RECV_DATA) |
|
|
dsi->un_flags;
|
|
un->un_dma_addr = 0;
|
|
un->un_dma_count = 0;
|
|
break;
|
|
|
|
case SC_INQUIRY:
|
|
DPRINTF("sfmkcdb: inquiry\n");
|
|
dsi->un_timeout = 2;
|
|
un->un_flags |= (SC_UNF_RECV_DATA | dsi->un_flags);
|
|
FORMG0COUNT(cdb, sizeof (struct scsi_inquiry_data));
|
|
un->un_dma_addr = (int)dsi->un_sense - (int)DVMA;
|
|
un->un_dma_count = sizeof (struct scsi_inquiry_data);
|
|
bzero((caddr_t)(dsi->un_sense), sizeof (struct scsi_inquiry_data));
|
|
break;
|
|
|
|
case SC_FORMAT:
|
|
EPRINTF("sfmkcdb: format\n");
|
|
DPRINTF1("sfmkcdb: count= 0x%d\n", un->un_count);
|
|
dsi->un_timeout = 60;
|
|
un->un_dma_addr = un->un_baddr;
|
|
un->un_flags = (un->un_flags & ~SC_UNF_RECV_DATA) |
|
|
dsi->un_flags;
|
|
/* cdb->fmt_parm_bits = FPB_BFI; XXXXX ???*/
|
|
cdb->fmt_parm_bits = 0;
|
|
un->un_dma_count = un->un_count;
|
|
cdb->fmt_interleave = 1;
|
|
break;
|
|
|
|
case SC_MODE_SELECT:
|
|
EPRINTF("sfmkcdb: mode select\n");
|
|
dsi->un_timeout = 2;
|
|
cdb->tag |= 0x10;
|
|
un->un_flags = (un->un_flags & ~SC_UNF_RECV_DATA) |
|
|
dsi->un_flags;
|
|
FORMG0COUNT(cdb, un->un_count);
|
|
un->un_dma_count = un->un_count;
|
|
un->un_dma_addr = (int)un->un_sbuf.b_un.b_addr - (int)DVMA;
|
|
/* un->un_dma_addr = un->un_baddr; */
|
|
break;
|
|
|
|
case SC_MODE_SENSE:
|
|
/* EPRINTF("sfmkcdb: mode sense\n"); */
|
|
dsi->un_timeout = 2;
|
|
un->un_flags |= (SC_UNF_RECV_DATA | dsi->un_flags);
|
|
FORMG0COUNT(cdb, un->un_count);
|
|
cdb->g0_addr1 = un->un_blkno;
|
|
un->un_dma_count = un->un_count;
|
|
un->un_dma_addr = (int)un->un_sbuf.b_un.b_addr - (int)DVMA;
|
|
/* un->un_dma_addr = un->un_baddr; */
|
|
break;
|
|
|
|
case SC_READ_DEFECT_LIST:
|
|
EPRINTF("sfmkcdb: read defect list- NOT SUPPORTED\n");
|
|
dsi->un_timeout = 4;
|
|
un->un_flags = (un->un_flags & ~SC_UNF_RECV_DATA) |
|
|
dsi->un_flags;
|
|
break;
|
|
|
|
case SC_REASSIGN_BLOCK:
|
|
EPRINTF1("sfmkcdb: reassign block 0x%x NOT SUPPORTED\n",
|
|
un->un_blkno);
|
|
dsi->un_timeout = 4;
|
|
un->un_flags = (un->un_flags & ~SC_UNF_RECV_DATA) |
|
|
dsi->un_flags;
|
|
break;
|
|
default:
|
|
EPRINTF("sfmkcdb: unknown command\n");
|
|
dsi->un_timeout = 4;
|
|
un->un_flags = (un->un_flags & ~SC_UNF_RECV_DATA) |
|
|
dsi->un_flags;
|
|
break;
|
|
}
|
|
dsi->un_last_cmd = un->un_cmd;
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* This routine handles controller interrupts.
|
|
* It is always called at disk interrupt priority.
|
|
*/
|
|
typedef enum sfintr_error_resolution {
|
|
real_error, /* Hard error */
|
|
psuedo_error, /* What looked like an error is actually OK */
|
|
more_processing /* Recoverable error */
|
|
} sfintr_error_resolution;
|
|
sfintr_error_resolution sferror();
|
|
|
|
sfintr(c, resid, error)
|
|
register struct scsi_ctlr *c;
|
|
u_int resid;
|
|
int error;
|
|
{
|
|
register struct scsi_unit *un;
|
|
register struct scsi_floppy *dsi;
|
|
register struct buf *bp;
|
|
register struct mb_device *md;
|
|
int status = 0;
|
|
int error_code = 0;
|
|
u_char severe = DK_NOERROR;
|
|
|
|
/* DPRINTF("sfintr:\n"); */
|
|
un = c->c_un;
|
|
md = un->un_md;
|
|
bp = md->md_utab.b_forw;
|
|
dsi = &sfdisk[SFUNIT(bp->b_dev)];
|
|
dsi->un_timeout = 0; /* Disable time-outs */
|
|
|
|
/* XXXX What it this? */
|
|
if (md->md_dk >= 0) {
|
|
dk_busy &= ~(1 << md->md_dk);
|
|
}
|
|
|
|
/*
|
|
* Check for error or special operation states and process.
|
|
* Otherwise, it was a normal I/O command which was successful.
|
|
*/
|
|
if (dsi->un_openf < OPEN || error || resid ) {
|
|
|
|
/*
|
|
* Special processing for SCSI bus failures.
|
|
*/
|
|
if (error == SE_FATAL) {
|
|
if (dsi->un_openf == OPEN) {
|
|
printf("sf%d: scsi bus failure\n", SFNUM(un));
|
|
}
|
|
dsi->un_retries = dsi->un_restores = 0;
|
|
dsi->un_err_severe = DK_FATAL;
|
|
un->un_present = 0;
|
|
dsi->un_openf = CLOSED;
|
|
bp->b_flags |= B_ERROR;
|
|
goto SFINTR_WRAPUP;
|
|
}
|
|
|
|
/*
|
|
* Opening disk, check if command failed. If it failed
|
|
* close device. Otherwise, it's open.
|
|
*/
|
|
if (dsi->un_openf == OPENING) {
|
|
if (error == SE_NO_ERROR) {
|
|
dsi->un_openf = OPEN;
|
|
goto SFINTR_SUCCESS;
|
|
} else if (error == SE_RETRYABLE) {
|
|
DPRINTF("sfintr: open failed\n");
|
|
dsi->un_openf = OPEN_FAILED;
|
|
bp->b_flags |= B_ERROR;
|
|
goto SFINTR_WRAPUP;
|
|
} else {
|
|
EPRINTF("sfintr: hardware failure\n");
|
|
dsi->un_openf = CLOSED;
|
|
bp->b_flags |= B_ERROR;
|
|
goto SFINTR_WRAPUP;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Rezero for failed command done, retry failed command
|
|
*/
|
|
if ((dsi->un_openf == RETRYING) &&
|
|
(un->un_cdb.cmd == SC_REZERO_UNIT)) {
|
|
|
|
if (error)
|
|
printf("sf%d: rezero failed\n", SFNUM(un));
|
|
|
|
DPRINTF("sfintr: rezero done\n");
|
|
un->un_flags &= ~SC_UNF_GET_SENSE;
|
|
un->un_cdb = un->un_saved_cmd.saved_cdb;
|
|
un->un_dma_addr = un->un_saved_cmd.saved_dma_addr;
|
|
un->un_dma_count = un->un_saved_cmd.saved_dma_count;
|
|
un->un_cmd = dsi->un_last_cmd;
|
|
sfmkcdb(un);
|
|
(*c->c_ss->scs_cmd)(c, un, 1);
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* Command failed, need to run request sense command.
|
|
*/
|
|
if ((dsi->un_openf == OPEN) && error) {
|
|
sfintr_sense(dsi, un, resid);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Request sense command done, restore failed command.
|
|
*/
|
|
if (dsi->un_openf == SENSING) {
|
|
DPRINTF("sfintr: restoring sense\n");
|
|
sfintr_ran_sense(un, dsi, &resid);
|
|
}
|
|
|
|
/*
|
|
* Reassign done, restore original state
|
|
*/
|
|
if (dsi->un_openf == MAPPING) {
|
|
DPRINTF("sfintr: restoring state\n");
|
|
sfintr_ran_reassign(un, dsi, &resid);
|
|
}
|
|
|
|
EPRINTF2("sfintr: retries= %d restores= %d ",
|
|
dsi->un_retries, dsi->un_restores);
|
|
EPRINTF1("total= %d\n", dsi->un_total_errors);
|
|
if ((dsi->un_openf == RETRYING) && (error == 0)) {
|
|
|
|
EPRINTF("sfintr: ok\n\n");
|
|
dsi->un_openf = OPEN;
|
|
dsi->un_retries = dsi->un_restores = 0;
|
|
dsi->un_err_severe = DK_RECOVERED;
|
|
goto SFINTR_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Process all other errors here
|
|
*/
|
|
#ifdef notdef
|
|
EPRINTF2("sfintr: processing error, error= %x chk= %x",
|
|
error, un->un_scb.chk);
|
|
EPRINTF1(" busy= %x", un->un_scb.busy);
|
|
#endif
|
|
EPRINTF2(" resid= %d (%d)\n", resid, un->un_dma_count);
|
|
switch (sferror(c, un, dsi, bp, resid, error)) {
|
|
case real_error:
|
|
/* This error is FATAL ! */
|
|
/* DPRINTF("sfintr: real error\n"); */
|
|
SF_PRINT_CMD(un);
|
|
dsi->un_retries = dsi->un_restores = 0;
|
|
bp->b_flags |= B_ERROR;
|
|
goto SFINTR_WRAPUP;
|
|
|
|
case psuedo_error:
|
|
/* A psuedo-error: soft error reported by ctlr */
|
|
DPRINTF("sfintr: psuedo error\n");
|
|
status = dsi->un_status;
|
|
error_code = dsi->un_err_code;
|
|
severe = dsi->un_err_severe;
|
|
dsi->un_retries = dsi->un_restores = 0;
|
|
goto SFINTR_SUCCESS;
|
|
|
|
case more_processing:
|
|
/* real error requiring error recovery */
|
|
/* DPRINTF("stintr: more processing\n"); */
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Handle successful Transfer. Also, take care of
|
|
* seek error problem by doing single sector I/O.
|
|
*/
|
|
SFINTR_SUCCESS:
|
|
dsi->un_status = status;
|
|
dsi->un_err_code = error_code;
|
|
dsi->un_err_severe = severe;
|
|
|
|
if (dsi->un_sec_left) {
|
|
EPRINTF("sfintr: single sector writes\n");
|
|
dsi->un_sec_left--;
|
|
un->un_baddr += SECSIZE;
|
|
un->un_blkno++;
|
|
sfmkcdb(un);
|
|
if ((*c->c_ss->scs_cmd)(c, un, 1) != 0)
|
|
printf("sf%d: single sector I/O failed\n", SFNUM(un));
|
|
}
|
|
|
|
|
|
/*
|
|
* Handle I/O request completion (both sucessful and failed).
|
|
*/
|
|
SFINTR_WRAPUP:
|
|
if (bp == &un->un_sbuf &&
|
|
((un->un_flags & SC_UNF_DVMA) == 0)) {
|
|
bp->b_resid = 0;
|
|
if (un->un_flags & SC_UNF_SPECIAL_DVMA)
|
|
mbudone(un->un_md);
|
|
else
|
|
(*c->c_ss->scs_done)(un->un_md);
|
|
|
|
} else {
|
|
bp->b_resid = bp->b_bcount - (un->un_count << SECDIV);
|
|
mbudone(un->un_md);
|
|
un->un_flags &= ~SC_UNF_DVMA;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Disk error decoder/handler.
|
|
*/
|
|
static sfintr_error_resolution
|
|
sferror(c, un, dsi, bp, resid, error)
|
|
register struct scsi_ctlr *c;
|
|
register struct scsi_unit *un;
|
|
register struct scsi_floppy *dsi;
|
|
struct buf *bp;
|
|
u_int resid;
|
|
int error;
|
|
{
|
|
register struct scsi_ext_sense *ssf;
|
|
|
|
ssf = (struct scsi_ext_sense *)dsi->un_sense;
|
|
/* DPRINTF("sferror:\n"); */
|
|
|
|
/*
|
|
* Special processing for driver command timeout errors.
|
|
*/
|
|
if (error == SE_TIMEOUT) {
|
|
EPRINTF("sferror: command timeout error\n");
|
|
dsi->un_status = SC_TIMEOUT;
|
|
goto SFERROR_RETRY;
|
|
}
|
|
|
|
/*
|
|
* Check for various check condition errors.
|
|
*/
|
|
dsi->un_total_errors++;
|
|
if (un->un_scb.chk) {
|
|
|
|
switch (ssf->key) {
|
|
case SC_RECOVERABLE_ERROR:
|
|
dsi->un_err_severe = DK_CORRECTED;
|
|
if (sf_retry == 0) {
|
|
sferrmsg(un, bp, "recoverable");
|
|
}
|
|
if (dsi->un_options & SD_NORETRY) {
|
|
dsi->un_err_severe = DK_CORRECTED;
|
|
return (real_error);
|
|
}
|
|
return (psuedo_error);
|
|
|
|
case SC_MEDIUM_ERROR:
|
|
EPRINTF("sferror: media error\n");
|
|
goto SFERROR_RETRY;
|
|
|
|
case SC_HARDWARE_ERROR:
|
|
EPRINTF("sferror: hardware error\n");
|
|
goto SFERROR_RETRY;
|
|
|
|
case SC_UNIT_ATTENTION:
|
|
EPRINTF("sferror: unit attention error\n");
|
|
goto SFERROR_RETRY;
|
|
|
|
case SC_NOT_READY:
|
|
EPRINTF("sferror: not ready\n");
|
|
dsi->un_err_severe = DK_FATAL;
|
|
return (real_error);
|
|
|
|
case SC_ILLEGAL_REQUEST:
|
|
EPRINTF("sferror: illegal request\n");
|
|
dsi->un_err_severe = DK_FATAL;
|
|
return (real_error);
|
|
|
|
case SC_VOLUME_OVERFLOW:
|
|
EPRINTF("sferror: volume overflow\n");
|
|
dsi->un_err_severe = DK_FATAL;
|
|
return (real_error);
|
|
|
|
case SC_WRITE_PROTECT:
|
|
EPRINTF("sferror: write protected\n");
|
|
dsi->un_err_severe = DK_FATAL;
|
|
return (real_error);
|
|
|
|
case SC_BLANK_CHECK:
|
|
EPRINTF("sferror: blank check\n");
|
|
dsi->un_err_severe = DK_FATAL;
|
|
return (real_error);
|
|
|
|
default:
|
|
/*
|
|
* Undecoded sense key. Try retries and hope
|
|
* that will fix the problem. Otherwise, we're
|
|
* dead.
|
|
*/
|
|
EPRINTF("sferror: undecoded sense key error\n");
|
|
SF_PRINT_CMD(un);
|
|
dsi->un_err_severe = DK_FATAL;
|
|
goto SFERROR_RETRY;
|
|
}
|
|
|
|
/*
|
|
* Process busy error. Try retries and hope that
|
|
* it'll be ready soon.
|
|
*/
|
|
} else if (un->un_scb.busy && !un->un_scb.is) {
|
|
EPRINTF1("sf%d: sferror: busy error\n", SFNUM(un));
|
|
SF_PRINT_CMD(un);
|
|
goto SFERROR_RETRY;
|
|
|
|
/*
|
|
* Process reservation error. Abort operation.
|
|
*/
|
|
} else if (un->un_scb.busy && un->un_scb.is) {
|
|
EPRINTF1("sf%d: sferror: reservation conflict error\n",
|
|
SFNUM(un));
|
|
SF_PRINT_CMD(un);
|
|
dsi->un_err_severe = DK_FATAL;
|
|
return (real_error);
|
|
|
|
/*
|
|
* Have left over residue data from last command.
|
|
* Do retries and hope this fixes it...
|
|
*/
|
|
} else if (resid != 0) {
|
|
EPRINTF1("sferror: residue error, residue= %d\n", resid);
|
|
SF_PRINT_CMD(un);
|
|
goto SFERROR_RETRY;
|
|
|
|
/*
|
|
* Have an unknown error. Don't know what went wrong.
|
|
* Do retries and hope this fixes it...
|
|
*/
|
|
} else {
|
|
EPRINTF("sferror: unknown error\n");
|
|
SF_PRINT_CMD(un);
|
|
dsi->un_err_severe = DK_FATAL;
|
|
goto SFERROR_RETRY;
|
|
}
|
|
|
|
/*
|
|
* Process command retries and rezeros here.
|
|
* Note, for on-line formatting, normal error
|
|
* recovery is inhibited.
|
|
*/
|
|
SFERROR_RETRY:
|
|
if (dsi->un_options & SD_NORETRY) {
|
|
EPRINTF("sferror: error recovery disabled\n");
|
|
sferrmsg(un, bp, "failed, no retries");
|
|
dsi->un_err_severe = DK_FATAL;
|
|
return (real_error);
|
|
}
|
|
|
|
/*
|
|
* Command failed, retry it.
|
|
*/
|
|
if (dsi->un_retries++ < MAX_RETRIES) {
|
|
if (((dsi->un_retries + dsi->un_restores) > sf_retry) ||
|
|
(dsi->un_restores != 0)) {
|
|
sferrmsg(un, bp, "retry");
|
|
}
|
|
|
|
dsi->un_openf = RETRYING;
|
|
sfmkcdb(un);
|
|
if ((*c->c_ss->scs_cmd)(c, un, 1) != 0) {
|
|
printf("sf%d: sferror: retry failed\n", SFNUM(un));
|
|
return (real_error);
|
|
}
|
|
return (more_processing);
|
|
|
|
/*
|
|
* Retries exhausted, try restore
|
|
*/
|
|
} else if (++dsi->un_restores < MAX_RESTORES) {
|
|
if (dsi->un_restores != EL_REST)
|
|
sferrmsg(un, bp, "restore");
|
|
|
|
/*
|
|
* Save away old command state.
|
|
*/
|
|
un->un_saved_cmd.saved_cdb = un->un_cdb;
|
|
un->un_saved_cmd.saved_dma_addr = un->un_dma_addr;
|
|
un->un_saved_cmd.saved_dma_count = un->un_dma_count;
|
|
dsi->un_openf = RETRYING;
|
|
dsi->un_retries = 0;
|
|
un->un_cmd = SC_REZERO_UNIT;
|
|
sfmkcdb(un);
|
|
(void) (*c->c_ss->scs_cmd)(c, un, 1);
|
|
return (more_processing);
|
|
|
|
/*
|
|
* Restores and retries exhausted, die!
|
|
*/
|
|
} else {
|
|
/* complete failure */
|
|
sferrmsg(un, bp, "failed");
|
|
dsi->un_openf = OPEN;
|
|
dsi->un_retries = 0;
|
|
dsi->un_restores = 0;
|
|
dsi->un_err_severe = DK_FATAL;
|
|
return (real_error);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Command failed, need to run a request sense command to determine why.
|
|
*/
|
|
static
|
|
sfintr_sense(dsi, un, resid)
|
|
register struct scsi_floppy *dsi;
|
|
register struct scsi_unit *un;
|
|
u_int resid;
|
|
{
|
|
|
|
/*
|
|
* Save away old command state.
|
|
*/
|
|
un->un_saved_cmd.saved_scb = un->un_scb;
|
|
un->un_saved_cmd.saved_cdb = un->un_cdb;
|
|
un->un_saved_cmd.saved_resid = resid;
|
|
un->un_saved_cmd.saved_dma_addr = un->un_dma_addr;
|
|
un->un_saved_cmd.saved_dma_count = un->un_dma_count;
|
|
/*
|
|
* Note that s?start will call sfmkcdb, which
|
|
* will notice that the flag is set and not do
|
|
* the copy of the cdb, doing a request sense
|
|
* rather than the normal command.
|
|
*/
|
|
/* DPRINTF("sfintr: getting sense\n"); */
|
|
un->un_flags |= SC_UNF_GET_SENSE;
|
|
dsi->un_openf = SENSING;
|
|
un->un_cmd = SC_REQUEST_SENSE;
|
|
(*un->un_c->c_ss->scs_go)(un->un_md);
|
|
}
|
|
|
|
|
|
/*
|
|
* Cleanup after running request sense command to see why the real
|
|
* command failed.
|
|
*/
|
|
static
|
|
sfintr_ran_sense(un, dsi, resid_ptr)
|
|
register struct scsi_unit *un;
|
|
register struct scsi_floppy *dsi;
|
|
u_int *resid_ptr;
|
|
{
|
|
register struct scsi_ext_sense *ssf;
|
|
|
|
/*
|
|
* Check if request sense command failed. This should
|
|
* never happen!
|
|
*/
|
|
un->un_flags &= ~SC_UNF_GET_SENSE;
|
|
dsi->un_openf = OPEN;
|
|
if (un->un_scb.chk) {
|
|
printf("sf%d: request sense failed\n",
|
|
SFNUM(un));
|
|
}
|
|
|
|
un->un_scb = un->un_saved_cmd.saved_scb;
|
|
un->un_cdb = un->un_saved_cmd.saved_cdb;
|
|
*resid_ptr = un->un_saved_cmd.saved_resid;
|
|
un->un_dma_addr = un->un_saved_cmd.saved_dma_addr;
|
|
un->un_dma_count = un->un_saved_cmd.saved_dma_count;
|
|
un->un_flags &= ~SC_UNF_GET_SENSE;
|
|
un->un_cmd = dsi->un_last_cmd;
|
|
dsi->un_openf = OPEN;
|
|
|
|
/*
|
|
* Log error information.
|
|
*/
|
|
ssf = (struct scsi_ext_sense *)dsi->un_sense;
|
|
dsi->un_err_resid = *resid_ptr;
|
|
dsi->un_status = ssf->key;
|
|
dsi->un_err_code = ssf->error_code;
|
|
|
|
dsi->un_err_blkno = (ssf->info_1 << 24) | (ssf->info_2 << 16) |
|
|
(ssf->info_3 << 8) | ssf->info_4;
|
|
if (dsi->un_err_blkno == 0 || !(ssf->adr_val)) {
|
|
/* No supplied block number, use original value */
|
|
EPRINTF("sfintr_ran_sense: synthesizing block number\n");
|
|
dsi->un_err_blkno = un->un_blkno;
|
|
}
|
|
|
|
#ifdef SFDEBUG
|
|
/* dump sense info on screen */
|
|
if (sf_debug > 1) {
|
|
sf_error_message(un, dsi);
|
|
printf("\n");
|
|
}
|
|
#endif SFDEBUG
|
|
}
|
|
|
|
|
|
/*
|
|
* Cleanup after running reassign block command.
|
|
*/
|
|
static
|
|
sfintr_ran_reassign(un, dsi, resid_ptr)
|
|
register struct scsi_unit *un;
|
|
register struct scsi_floppy *dsi;
|
|
register u_int *resid_ptr;
|
|
{
|
|
/*
|
|
* Check if reassign command failed.
|
|
*/
|
|
un->un_flags &= ~SC_UNF_GET_SENSE;
|
|
dsi->un_openf = OPEN;
|
|
if (un->un_scb.chk)
|
|
printf("sf%d: reassign block failed\n", SFNUM(un));
|
|
|
|
un->un_scb = un->un_saved_cmd.saved_scb;
|
|
un->un_cdb = un->un_saved_cmd.saved_cdb;
|
|
*resid_ptr = un->un_saved_cmd.saved_resid;
|
|
un->un_dma_addr = un->un_saved_cmd.saved_dma_addr;
|
|
un->un_dma_count = un->un_saved_cmd.saved_dma_count;
|
|
un->un_flags &= ~SC_UNF_GET_SENSE;
|
|
un->un_cmd = dsi->un_last_cmd;
|
|
dsi->un_openf = OPEN;
|
|
}
|
|
|
|
|
|
/*
|
|
* This routine performs raw read operations. It is called from the
|
|
* device switch at normal priority. It uses a per-unit buffer for the
|
|
* operation.
|
|
*/
|
|
sfread(dev, uio)
|
|
dev_t dev;
|
|
struct uio *uio;
|
|
{
|
|
register struct scsi_unit *un;
|
|
register int unit;
|
|
|
|
/* DPRINTF("sfread:\n"); */
|
|
unit = SFUNIT(dev);
|
|
if (unit >= nsfdisk) {
|
|
EPRINTF("sfread: invalid unit\n");
|
|
return (ENXIO);
|
|
}
|
|
/*
|
|
* The following tests assume a block size which is power of 2.
|
|
* This allows a bit mask operation to be used instead of a
|
|
* divide operation thus saving considerable time.
|
|
*/
|
|
if (uio->uio_offset & (DEV_BSIZE -1)) {
|
|
EPRINTF1("sfread: block address not modulo %d\n",
|
|
DEV_BSIZE);
|
|
return (EINVAL);
|
|
}
|
|
if (uio->uio_iov->iov_len & (DEV_BSIZE -1)) {
|
|
tracedump();
|
|
EPRINTF2("sfread: block length not modulo %d %d\n",
|
|
DEV_BSIZE, uio->uio_iov->iov_len);
|
|
return (EINVAL);
|
|
}
|
|
un = &sfunits[unit];
|
|
return (physio(sfstrategy, &un->un_rbuf, dev, B_READ, minphys, uio));
|
|
}
|
|
|
|
|
|
/*
|
|
* This routine performs raw write operations. It is called from the
|
|
* device switch at normal priority. It uses a per-unit buffer for the
|
|
* operation.
|
|
*/
|
|
sfwrite(dev, uio)
|
|
dev_t dev;
|
|
struct uio *uio;
|
|
{
|
|
register struct scsi_unit *un;
|
|
register int unit;
|
|
|
|
/* DPRINTF("sfwrite:\n"); */
|
|
unit = SFUNIT(dev);
|
|
if (unit >= nsfdisk) {
|
|
EPRINTF("sfwrite: invalid unit\n");
|
|
return (ENXIO);
|
|
}
|
|
/*
|
|
* The following tests assume a block size which is power of 2.
|
|
* This allows a bit mask operation to be used instead of a
|
|
* divide operation thus saving considerable time.
|
|
*/
|
|
if (uio->uio_offset & (DEV_BSIZE -1)) {
|
|
EPRINTF1("sfwrite: block address not modulo %d\n",
|
|
DEV_BSIZE);
|
|
return (EINVAL);
|
|
}
|
|
if (uio->uio_iov->iov_len & (DEV_BSIZE -1)) {
|
|
EPRINTF1("sfwrite: block length not modulo %d\n",
|
|
DEV_BSIZE);
|
|
return (EINVAL);
|
|
}
|
|
un = &sfunits[unit];
|
|
return (physio(sfstrategy, &un->un_rbuf, dev, B_WRITE, minphys, uio));
|
|
}
|
|
|
|
|
|
/*
|
|
* This routine implements the ioctl calls. It is called
|
|
* from the device switch at normal priority.
|
|
*/
|
|
/*ARGSUSED*/
|
|
sfioctl(dev, cmd, data, flag)
|
|
dev_t dev;
|
|
register int cmd;
|
|
register caddr_t data;
|
|
int flag;
|
|
{
|
|
register struct scsi_unit *un;
|
|
register struct scsi_floppy *dsi;
|
|
register struct dk_map *lp;
|
|
register struct dk_info *info;
|
|
#ifdef SF_FORMAT
|
|
register struct dk_conf *conf;
|
|
#endif SF_FORMAT
|
|
register struct dk_diag *diag;
|
|
register struct fdk_char *fchar;
|
|
register int unit;
|
|
register int i;
|
|
int s;
|
|
struct ms_med_parms {
|
|
struct ccs_modesel_head_fl header;
|
|
struct ccs_modesel_medium page5;
|
|
} *ms_med_parms, *oms_med_parms;
|
|
|
|
/* DPRINTF("sfioctl:\n"); */
|
|
unit = SFUNIT(dev);
|
|
if (unit >= nsfdisk) {
|
|
EPRINTF("sfioctl: invalid unit\n");
|
|
return (ENXIO);
|
|
}
|
|
un = &sfunits[unit];
|
|
dsi = &sfdisk[unit];
|
|
lp = &dsi->un_map[LPART(dev)];
|
|
switch (cmd) {
|
|
|
|
/*
|
|
* Return info concerning the controller.
|
|
*/
|
|
case DKIOCINFO:
|
|
DPRINTF("sfioctl: get info\n");
|
|
info = (struct dk_info *)data;
|
|
info->dki_ctlr = getdevaddr(un->un_mc->mc_addr);
|
|
info->dki_unit = un->un_md->md_slave;
|
|
|
|
switch (dsi->un_ctype) {
|
|
case CTYPE_NCRFLOP:
|
|
info->dki_ctype = DKC_NCRFLOPPY;
|
|
break;
|
|
default:
|
|
info->dki_ctype = DKC_SCSI_CCS;
|
|
break;
|
|
}
|
|
info->dki_flags = DKI_FMTVOL;
|
|
return (0);
|
|
|
|
/*
|
|
* Return the geometry of the specified unit.
|
|
*/
|
|
case DKIOCGGEOM:
|
|
DPRINTF("sfioctl: get geometry\n");
|
|
*(struct dk_geom *)data = dsi->un_g;
|
|
return (0);
|
|
|
|
/*
|
|
* Set the geometry of the specified unit.
|
|
*/
|
|
case DKIOCSGEOM:
|
|
EPRINTF("sfioctl: set geometry\n");
|
|
dsi->un_g = *(struct dk_geom *)data;
|
|
return (0);
|
|
|
|
/*
|
|
* Return the map for the specified logical partition.
|
|
* This has been made obsolete by the get all partitions
|
|
* command.
|
|
*/
|
|
case DKIOCGPART:
|
|
DPRINTF("sfioctl: get partition\n");
|
|
*(struct dk_map *)data = *lp;
|
|
return (0);
|
|
|
|
/*
|
|
* Set the map for the specified logical partition.
|
|
* This has been made obsolete by the set all partitions
|
|
* command. We raise the priority just to make sure
|
|
* an interrupt doesn't come in while the map is
|
|
* half updated.
|
|
*/
|
|
case DKIOCSPART:
|
|
EPRINTF("sfioctl: set partitions\n");
|
|
*lp = *(struct dk_map *)data;
|
|
return (0);
|
|
|
|
/*
|
|
* Return configuration info
|
|
*/
|
|
case DKIOCGCONF:
|
|
#ifdef SF_FORMAT
|
|
DPRINTF("sfioctl: get configuration info\n");
|
|
conf = (struct dk_conf *)data;
|
|
switch (dsi->un_ctype) {
|
|
case CTYPE_NCRFLOP:
|
|
conf->dkc_ctype = DKC_NCRFLOPPY;
|
|
break;
|
|
default:
|
|
conf->dkc_ctype = DKC_SCSI_CCS;
|
|
break;
|
|
}
|
|
(void) strncpy(conf->dkc_dname, "sf", DK_DEVLEN);
|
|
conf->dkc_flags = DKI_FMTVOL;
|
|
conf->dkc_cnum = un->un_mc->mc_ctlr;
|
|
conf->dkc_addr = getdevaddr(un->un_mc->mc_addr);
|
|
conf->dkc_space = un->un_mc->mc_space;
|
|
conf->dkc_prio = un->un_mc->mc_intpri;
|
|
if (un->un_mc->mc_intr)
|
|
conf->dkc_vec = un->un_mc->mc_intr->v_vec;
|
|
else
|
|
conf->dkc_vec = 0;
|
|
(void) strncpy(conf->dkc_cname, un->un_c->c_name, DK_DEVLEN);
|
|
conf->dkc_unit = un->un_md->md_unit;
|
|
conf->dkc_slave = un->un_md->md_slave;
|
|
#endif SF_FORMAT
|
|
return (0);
|
|
|
|
/*
|
|
* Return the map for all logical partitions.
|
|
*/
|
|
case DKIOCGAPART:
|
|
DPRINTF("sfioctl: get all logical partitions\n");
|
|
for (i = 0; i < NLPART; i++)
|
|
((struct dk_map *)data)[i] = dsi->un_map[i];
|
|
return (0);
|
|
|
|
/*
|
|
* Set the map for all logical partitions. We raise
|
|
* the priority just to make sure an interrupt doesn't
|
|
* come in while the map is half updated.
|
|
*/
|
|
case DKIOCSAPART:
|
|
EPRINTF("sfioctl: set all logical partitions\n");
|
|
s = splr(pritospl(un->un_mc->mc_intpri));
|
|
for (i = 0; i < NLPART; i++)
|
|
dsi->un_map[i] = ((struct dk_map *)data)[i];
|
|
(void) splx(s);
|
|
return (0);
|
|
|
|
/*
|
|
* Get error status from last command.
|
|
*/
|
|
case DKIOCGDIAG:
|
|
EPRINTF("sfioctl: get error status\n");
|
|
diag = (struct dk_diag *) data;
|
|
diag->dkd_errcmd = dsi->un_last_cmd;
|
|
diag->dkd_errsect = dsi->un_err_blkno;
|
|
diag->dkd_errno = dsi->un_status;
|
|
/* diag->dkd_errno = dsi->un_err_code; */
|
|
#ifdef SF_FORMAT
|
|
diag->dkd_severe = dsi->un_err_severe;
|
|
#endif SF_FORMAT
|
|
|
|
dsi->un_last_cmd = 0; /* Reset */
|
|
dsi->un_err_blkno = 0;
|
|
dsi->un_err_code = 0;
|
|
dsi->un_err_severe = 0;
|
|
return (0);
|
|
|
|
/*
|
|
* Run a generic command.
|
|
*/
|
|
case FDKIOCSCMD:
|
|
case DKIOCSCMD:
|
|
#ifdef SF_FORMAT
|
|
/* DPRINTF("sfioctl: run special command\n"); */
|
|
return (sfioctl_cmd(dev, un, dsi, data));
|
|
#endif SF_FORMAT
|
|
|
|
case FDKIOGCHAR:
|
|
DPRINTF("sfioctl: get characteristics\n");
|
|
fchar = (struct fdk_char *)data;
|
|
/* request page 5 stuff */
|
|
ms_med_parms = (struct ms_med_parms *)rmalloc(iopbmap,
|
|
(long)(sizeof (struct ms_med_parms) + 4));
|
|
oms_med_parms = ms_med_parms;
|
|
while ((u_int)ms_med_parms & 0x03)
|
|
((u_int)ms_med_parms)++;
|
|
bzero((char *)ms_med_parms, sizeof (struct ms_med_parms));
|
|
s = splr(pritospl(un->un_mc->mc_intpri));
|
|
if (sfcmd(dev, SC_MODE_SENSE, 0x5,
|
|
sizeof (struct ms_med_parms),
|
|
(caddr_t)ms_med_parms, 0)) {
|
|
EPRINTF("Can not get characteristics\n");
|
|
(void) splx(s);
|
|
return (ENXIO);
|
|
}
|
|
(void) splx(s);
|
|
|
|
fchar->medium = ms_med_parms->header.medium;
|
|
fchar->transfer_rate = ms_med_parms->page5.xfer_rate;
|
|
fchar->ncyl = ms_med_parms->page5.ncyl;
|
|
fchar->nhead = ms_med_parms->page5.nhead;
|
|
fchar->sec_size = ms_med_parms->page5.data_bytes;
|
|
fchar->secptrack = ms_med_parms->page5.sec_trk ;
|
|
rmfree(iopbmap, (long)(sizeof (struct ms_med_parms) + 4),
|
|
(u_long)oms_med_parms);
|
|
return (0);
|
|
|
|
case FDKIOSCHAR:
|
|
DPRINTF("sfioctl: set characteristics\n");
|
|
fchar = (struct fdk_char *)data;
|
|
ms_med_parms = (struct ms_med_parms *)rmalloc(iopbmap,
|
|
(long)(sizeof (struct ms_med_parms) + 4));
|
|
oms_med_parms = ms_med_parms;
|
|
while ((u_int)ms_med_parms & 0x03)
|
|
((u_int)ms_med_parms)++;
|
|
bzero((char *)ms_med_parms, sizeof (struct ms_med_parms));
|
|
s = splr(pritospl(un->un_mc->mc_intpri));
|
|
if (sfcmd(dev, SC_MODE_SENSE, 0x5,
|
|
sizeof (struct ms_med_parms),
|
|
(caddr_t)ms_med_parms, 0)) {
|
|
EPRINTF("Can not get characteristics\n");
|
|
rmfree(iopbmap, (long)(sizeof (struct ms_med_parms) + 4),
|
|
(u_long)oms_med_parms);
|
|
|
|
(void) splx(s);
|
|
return(ENXIO);
|
|
}
|
|
/* stuff set by user */
|
|
ms_med_parms->header.medium = fchar->medium;
|
|
ms_med_parms->page5.xfer_rate = fchar->transfer_rate;
|
|
ms_med_parms->page5.nhead = fchar->nhead;
|
|
ms_med_parms->page5.sec_trk = fchar->secptrack;
|
|
ms_med_parms->page5.data_bytes = fchar->sec_size;
|
|
ms_med_parms->page5.ncyl = fchar->ncyl;
|
|
if (sfcmd(dev, SC_MODE_SELECT, 0x5,
|
|
sizeof (struct ms_med_parms),
|
|
(caddr_t)ms_med_parms, 0)) {
|
|
EPRINTF("Can not set characteristics\n");
|
|
rmfree(iopbmap, (long)(sizeof (struct ms_med_parms) + 4),
|
|
(u_long)oms_med_parms);
|
|
(void) splx(s);
|
|
return (ENXIO);
|
|
}
|
|
(void) splx(s);
|
|
rmfree(iopbmap, (long)(sizeof (struct ms_med_parms) + 4),
|
|
(u_long)oms_med_parms);
|
|
return (0);
|
|
|
|
/*
|
|
* Handle unknown ioctls here.
|
|
*/
|
|
default:
|
|
EPRINTF("sfioctl: unknown ioctl\n");
|
|
return (ENOTTY);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Run a command for sfioctl.
|
|
*/
|
|
#ifdef SF_FORMAT
|
|
/*ARGSUSED*/
|
|
static
|
|
sfioctl_cmd(dev, un, dsi, data)
|
|
dev_t dev;
|
|
register struct scsi_unit *un;
|
|
struct scsi_floppy *dsi;
|
|
caddr_t data;
|
|
{
|
|
register struct dk_cmd *com;
|
|
register struct fdk_state *flstate;
|
|
int err, options;
|
|
int s;
|
|
|
|
/* DPRINTF("sfioctl_cmd:\n"); */
|
|
|
|
com = (struct dk_cmd *)&((struct fdk_cmd *)data)->dcmd;
|
|
flstate = (struct fdk_state *)&((struct fdk_cmd *)data)->fstate;
|
|
#ifdef SFDEBUG
|
|
#ifdef notdef
|
|
if (sf_debug > 1) {
|
|
printf("sfioctl_cmd: cmd= %x blk= %x cnt= %x ",
|
|
com->dkc_cmd, com->dkc_blkno, com->dkc_secnt);
|
|
printf("buf addr= %x buflen= 0x%x\n",
|
|
com->dkc_bufaddr, com->dkc_buflen);
|
|
}
|
|
#endif
|
|
#endif SFDEBUG
|
|
/*
|
|
* Set options.
|
|
*/
|
|
options = 0;
|
|
if (com->dkc_flags & DK_SILENT) {
|
|
options |= SD_SILENT;
|
|
#ifdef SFDEBUG
|
|
if (sf_debug > 0)
|
|
options &= ~SD_SILENT;
|
|
#endif SFDEBUG
|
|
}
|
|
if (com->dkc_flags & DK_ISOLATE)
|
|
options |= SD_NORETRY;
|
|
|
|
/*
|
|
* Process the special ioctl command.
|
|
*/
|
|
switch (com->dkc_cmd) {
|
|
case FKREAD:
|
|
/* DPRINTF("sfioctl_cmd: read\n"); */
|
|
s = splr(pritospl(un->un_mc->mc_intpri));
|
|
err = sf_check_char(flstate, un, dev);
|
|
/* make sure we have not changed */
|
|
options |= SD_DVMA_RD;
|
|
err = sfcmd(dev, SC_SPECIAL_READ, (u_int)com->dkc_blkno,
|
|
(u_int)com->dkc_buflen,
|
|
(caddr_t)com->dkc_bufaddr, options);
|
|
(void) splx(s);
|
|
break;
|
|
|
|
case FKWRITE:
|
|
/* DPRINTF("sfioctl_cmd: write\n"); */
|
|
s = splr(pritospl(un->un_mc->mc_intpri));
|
|
err = sf_check_char(flstate, un, dev);
|
|
/* make sure we have not changed */
|
|
options |= SD_DVMA_WR;
|
|
err = sfcmd(dev, SC_SPECIAL_WRITE, (u_int)com->dkc_blkno,
|
|
(u_int)com->dkc_buflen,
|
|
(caddr_t)com->dkc_bufaddr, options);
|
|
(void) splx(s);
|
|
break;
|
|
|
|
case FKSEEK:
|
|
DPRINTF("sfioctl_cmd: seek\n");
|
|
s = splr(pritospl(un->un_mc->mc_intpri));
|
|
err = sfcmd(dev, SC_SEEK, (u_int)com->dkc_blkno,
|
|
(u_int)com->dkc_buflen,
|
|
(caddr_t)com->dkc_bufaddr, options);
|
|
(void) splx(s);
|
|
break;
|
|
|
|
case FKREZERO:
|
|
DPRINTF("sfioctl_cmd: rezero\n");
|
|
s = splr(pritospl(un->un_mc->mc_intpri));
|
|
err = sfcmd(dev, SC_REZERO_UNIT, (u_int)com->dkc_blkno,
|
|
(u_int)com->dkc_buflen,
|
|
(caddr_t)com->dkc_bufaddr, options);
|
|
(void) splx(s);
|
|
break;
|
|
|
|
case SC_MODE_SELECT:
|
|
EPRINTF("sfioctl_cmd: mode select\n");
|
|
options |= SD_DVMA_WR;
|
|
s = splr(pritospl(un->un_mc->mc_intpri));
|
|
err = sfcmd(dev, SC_MODE_SELECT, (u_int)com->dkc_blkno,
|
|
(u_int)com->dkc_buflen, (caddr_t)com->dkc_bufaddr,
|
|
options);
|
|
(void) splx(s);
|
|
#ifdef SFDEBUG
|
|
if (sf_debug > 2) {
|
|
sf_print_buffer((u_char *)com->dkc_bufaddr,
|
|
(int)com->dkc_buflen);
|
|
printf("\n");
|
|
}
|
|
#endif SFDEBUG
|
|
break;
|
|
|
|
case SC_MODE_SENSE:
|
|
EPRINTF("sfioctl_cmd: mode sense\n");
|
|
options |= SD_DVMA_RD;
|
|
s = splr(pritospl(un->un_mc->mc_intpri));
|
|
err = sfcmd(dev, SC_MODE_SENSE, (u_int)com->dkc_blkno,
|
|
(u_int)com->dkc_buflen, (caddr_t)com->dkc_bufaddr,
|
|
options);
|
|
(void) splx(s);
|
|
#ifdef SFDEBUG
|
|
if (sf_debug > 2) {
|
|
sf_print_buffer((u_char *)com->dkc_bufaddr,
|
|
(int)com->dkc_buflen);
|
|
printf("\n");
|
|
}
|
|
#endif SFDEBUG
|
|
break;
|
|
|
|
case FKFORMAT_TRACK:
|
|
EPRINTF("sfioctl_cmd: format track\n");
|
|
s = splr(pritospl(un->un_mc->mc_intpri));
|
|
err = sf_check_char(flstate, un, dev);
|
|
err = sfcmd(dev, SC_REZERO_UNIT, (u_int)com->dkc_blkno,
|
|
(u_int)com->dkc_buflen,
|
|
(caddr_t)com->dkc_bufaddr, options);
|
|
err = sfcmd(dev, SC_FORMAT_TRACK, (u_int)com->dkc_blkno,
|
|
(u_int)com->dkc_buflen, (caddr_t)com->dkc_bufaddr,
|
|
options);
|
|
(void) splx(s);
|
|
break;
|
|
|
|
case FKFORMAT_UNIT:
|
|
/* EPRINTF("sfioctl_cmd: format\n"); */
|
|
s = splr(pritospl(un->un_mc->mc_intpri));
|
|
err = sf_check_char(flstate, un, dev);
|
|
err = sfcmd(dev, SC_FORMAT, (u_int)com->dkc_blkno,
|
|
(u_int)com->dkc_buflen, (caddr_t)com->dkc_bufaddr,
|
|
options);
|
|
(void) splx(s);
|
|
break;
|
|
|
|
default:
|
|
EPRINTF1("sfioctl_cmd: unknown command %x\n", com->dkc_cmd);
|
|
return (EINVAL);
|
|
/* break; */
|
|
}
|
|
if (err) {
|
|
/* EPRINTF("sfioctl_cmd: ioctl cmd failed\n"); */
|
|
return (EIO);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
/* see if any of the characteristics of the floppy have changed */
|
|
sf_check_char(fchar, un, dev)
|
|
struct fdk_state *fchar;
|
|
register struct scsi_unit *un;
|
|
dev_t dev;
|
|
{
|
|
register struct scsi_floppy *sfp;
|
|
struct ms_med_parms {
|
|
struct ccs_modesel_head_fl header;
|
|
struct ccs_modesel_medium page5;
|
|
} *ms_med_parms, *oms_med_parms;
|
|
int change = 0;
|
|
|
|
sfp = &sfdisk[un->un_unit];
|
|
if (fchar->fkc_bsec || fchar->fkc_strack ||
|
|
fchar->fkc_step || fchar->fkc_rate) {
|
|
ms_med_parms = (struct ms_med_parms *)rmalloc(iopbmap,
|
|
(long)(sizeof (struct ms_med_parms) + 4));
|
|
oms_med_parms = ms_med_parms;
|
|
while ((u_int)ms_med_parms & 0x03)
|
|
((u_int)ms_med_parms)++;
|
|
bzero((char *)ms_med_parms, sizeof (struct ms_med_parms));
|
|
/* stuff set by user */
|
|
if (fchar->fkc_rate != sfp->sf_xrate) {
|
|
sfp->sf_xrate = fchar->fkc_rate;
|
|
change = 1;
|
|
}
|
|
if (fchar->fkc_strack != sfp->sf_spt) {
|
|
sfp->sf_spt = fchar->fkc_strack;
|
|
change = 1;
|
|
}
|
|
if (fchar->fkc_bsec != sfp->sf_bsec) {
|
|
sfp->sf_bsec = fchar->fkc_bsec;
|
|
change = 1;
|
|
}
|
|
if (fchar->fkc_step != sfp->sf_step) {
|
|
sfp->sf_step = fchar->fkc_step;
|
|
change = 1;
|
|
}
|
|
if (change) {
|
|
if (sfcmd(dev, SC_MODE_SENSE, 0x5,
|
|
sizeof (struct ms_med_parms),
|
|
(caddr_t)ms_med_parms, 0)) {
|
|
EPRINTF("Can not get characteristics\n");
|
|
rmfree(iopbmap, (long)(sizeof (struct ms_med_parms) + 4),
|
|
(u_long)oms_med_parms);
|
|
return(ENXIO);
|
|
}
|
|
ms_med_parms->page5.xfer_rate = sfp->sf_xrate;
|
|
ms_med_parms->page5.sec_trk = sfp->sf_spt;
|
|
ms_med_parms->page5.data_bytes = sfp->sf_bsec;
|
|
ms_med_parms->page5.step = sfp->sf_step;
|
|
#ifdef notdef
|
|
if (sfcmd(dev, SC_MODE_SELECT, 0x5,
|
|
sizeof (struct ms_med_parms),
|
|
(caddr_t)ms_med_parms, 0)) {
|
|
EPRINTF("Can not set characteristics\n");
|
|
rmfree(iopbmap, (long)(sizeof (struct ms_med_parms) + 4),
|
|
(u_long)oms_med_parms);
|
|
return (ENXIO);
|
|
}
|
|
#endif
|
|
}
|
|
rmfree(iopbmap, (long)(sizeof (struct ms_med_parms) + 4),
|
|
(u_long)oms_med_parms);
|
|
return (0);
|
|
}
|
|
return (0);
|
|
}
|
|
#endif SF_FORMAT
|
|
|
|
|
|
static char *sf_ncrflop_error_str[] = {
|
|
"", /* 0x00 */
|
|
"no index", /* 0x01 */
|
|
"seek incomplete", /* 0x02 */
|
|
"write fault", /* 0x03 */
|
|
"drive not ready", /* 0x04 */
|
|
"drive not selected", /* 0x05 */
|
|
"no track 0", /* 0x06 */
|
|
"multiple drives selected", /* 0x07 */
|
|
"lun failure", /* 0x08 */
|
|
"servo error", /* 0x09 */
|
|
"", /* 0x0a */
|
|
"", /* 0x0b */
|
|
"", /* 0x0c */
|
|
"", /* 0x0d */
|
|
"", /* 0x0e */
|
|
"", /* 0x0f */
|
|
"ID error", /* 0x10 */
|
|
"hard data error", /* 0x11 */
|
|
"no addr mark", /* 0x12 */
|
|
"no data field addr mark", /* 0x13 */
|
|
"block not found", /* 0x14 */
|
|
"seek error", /* 0x15 */
|
|
"dma timeout", /* 0x16 */
|
|
"recoverable error", /* 0x17 */
|
|
"soft data error", /* 0x18 */
|
|
"bad block", /* 0x19 */
|
|
"parameter overrun", /* 0x1a */
|
|
"synchronous xfer error", /* 0x1b */
|
|
"no primary defect list", /* 0x1c */
|
|
"compare error", /* 0x1d */
|
|
"recoverable error", /* 0x1e */
|
|
"", /* 0x1f */
|
|
"invalid command", /* 0x20 */
|
|
"invalid block", /* 0x21 */
|
|
"illegal command", /* 0x22 */
|
|
"", /* 0x23 */
|
|
"invalid cdb", /* 0x24 */
|
|
"invalid lun", /* 0x25 */
|
|
"invalid param list", /* 0x26 */
|
|
"write protected", /* 0x27 */
|
|
"media changed", /* 0x28 */
|
|
"reset", /* 0x29 */
|
|
"mode select changed", /* 0x2a */
|
|
0
|
|
};
|
|
#define MAX_NCRFLOP_ERROR_STR \
|
|
(sizeof(sf_ncrflop_error_str)/sizeof(sf_ncrflop_error_str[0]))
|
|
|
|
|
|
static char *sf_key_error_str[] = {
|
|
"no sense", /* 0x00 */
|
|
"soft error", /* 0x01 */
|
|
"not ready", /* 0x02 */
|
|
"medium error", /* 0x03 */
|
|
"hardware error", /* 0x04 */
|
|
"illegal request", /* 0x05 */
|
|
"unit attention", /* 0x06 */
|
|
"write protected", /* 0x07 */
|
|
"blank check", /* 0x08 */
|
|
"vendor unique", /* 0x09 */
|
|
"copy aborted", /* 0x0a */
|
|
"aborted command", /* 0x0b */
|
|
"equal error", /* 0x0c */
|
|
"volume overflow", /* 0x0d */
|
|
"miscompare error", /* 0x0e */
|
|
"reserved", /* 0x0f */
|
|
0
|
|
};
|
|
#define MAX_KEY_ERROR_STR \
|
|
(sizeof(sf_key_error_str)/sizeof(sf_key_error_str[0]))
|
|
|
|
|
|
static char *sf_cmds[] = {
|
|
"test unit ready", /* 0x00 */
|
|
"rezero", /* 0x01 */
|
|
"<bad cmd>", /* 0x02 */
|
|
"request sense", /* 0x03 */
|
|
"format", /* 0x04 */
|
|
"<bad cmd>", /* 0x05 */
|
|
"<bad cmd>", /* 0x06 */
|
|
"reassign", /* 0x07 */
|
|
"read", /* 0x08 */
|
|
"<bad cmd>", /* 0x09 */
|
|
"write", /* 0x0a */
|
|
"seek", /* 0x0b */
|
|
"<bad cmd>", /* 0x0c */
|
|
"<bad cmd>", /* 0x0d */
|
|
"<bad cmd>", /* 0x0e */
|
|
"<bad cmd>", /* 0x0f */
|
|
"<bad cmd>", /* 0x10 */
|
|
"<bad cmd>", /* 0x11 */
|
|
"inquiry", /* 0x12 */
|
|
"<bad cmd>", /* 0x13 */
|
|
"<bad cmd>", /* 0x14 */
|
|
"mode select", /* 0x15 */
|
|
"reserve", /* 0x16 */
|
|
"release", /* 0x17 */
|
|
"copy", /* 0x18 */
|
|
"<bad cmd>", /* 0x19 */
|
|
"mode sense", /* 0x1a */
|
|
"start/stop", /* 0x1b */
|
|
"<bad cmd>", /* 0x1c */
|
|
};
|
|
#define MAX_SF_CMDS \
|
|
(sizeof(sf_cmds)/sizeof(sf_cmds[0]))
|
|
|
|
|
|
/*
|
|
* Return the text string associated with the sense key value.
|
|
*/
|
|
static char *
|
|
sf_print_key(key_code)
|
|
register u_char key_code;
|
|
{
|
|
static char *unknown_key = "unknown key";
|
|
if ((key_code > MAX_KEY_ERROR_STR -1) ||
|
|
sf_key_error_str[key_code] == NULL) {
|
|
|
|
return (unknown_key);
|
|
}
|
|
return (sf_key_error_str[key_code]);
|
|
}
|
|
|
|
|
|
/*
|
|
* Return the text string associated with the secondary
|
|
* error code, if availiable.
|
|
*/
|
|
static char *
|
|
sf_print_error(dsi, error_code)
|
|
register struct scsi_floppy *dsi;
|
|
register u_char error_code;
|
|
{
|
|
static char *unknown_error = "unknown error";
|
|
switch (dsi->un_ctype) {
|
|
case CTYPE_NCRFLOP:
|
|
case CTYPE_CCS:
|
|
if ((MAX_NCRFLOP_ERROR_STR > error_code) &&
|
|
sf_ncrflop_error_str[error_code] != NULL)
|
|
return (sf_ncrflop_error_str[error_code]);
|
|
break;
|
|
|
|
}
|
|
return (unknown_error);
|
|
}
|
|
|
|
|
|
/*
|
|
* Print the sense key and secondary error codes
|
|
* and dump out the sense bytes.
|
|
*/
|
|
#ifdef SFDEBUG
|
|
static
|
|
sf_error_message(un, dsi)
|
|
register struct scsi_unit *un;
|
|
register struct scsi_floppy *dsi;
|
|
{
|
|
register struct scsi_ext_sense *ssf;
|
|
register u_char *cp;
|
|
register int i;
|
|
register u_char error_code;
|
|
|
|
/* If error messages are being suppressed, exit. */
|
|
if (dsi->un_options & SD_SILENT)
|
|
return;
|
|
|
|
ssf = (struct scsi_ext_sense *)cp = (
|
|
struct scsi_ext_sense *)dsi->un_sense;
|
|
error_code = ssf->error_code;
|
|
printf("sf%d error: sense key(0x%x): %s",
|
|
un - sfunits, ssf->key, sf_print_key(ssf->key));
|
|
if (error_code != 0) {
|
|
printf(", error code(0x%x): %s",
|
|
error_code, sf_print_error(dsi, error_code));
|
|
}
|
|
|
|
printf("\n sense = ");
|
|
for (i=0; i < sizeof (struct scsi_ext_sense); i++)
|
|
printf("%x ", *cp++);
|
|
printf("\n");
|
|
}
|
|
|
|
|
|
static
|
|
sf_print_cmd(un)
|
|
register struct scsi_unit *un;
|
|
{
|
|
register int x;
|
|
register u_char *y = (u_char *)&(un->un_cdb);
|
|
|
|
printf("sf%d: failed cmd = ", SFUNIT(un->un_unit));
|
|
for (x = 0; x < CDB_GROUP0; x++)
|
|
printf("%x ", *y++);
|
|
printf("\n");
|
|
}
|
|
#endif SFDEBUG
|
|
|
|
|
|
static
|
|
sferrmsg(un, bp, action)
|
|
struct scsi_unit *un;
|
|
struct buf *bp;
|
|
char *action;
|
|
{
|
|
register struct scsi_ext_sense *ssf;
|
|
register struct scsi_floppy *dsi;
|
|
char *cmdname;
|
|
u_char error_code;
|
|
int blkno_flag = 1; /* if false, blkno is meaningless */
|
|
|
|
dsi = &sfdisk[dkunit(bp)];
|
|
ssf = (struct scsi_ext_sense *)dsi->un_sense;
|
|
|
|
/* If error messages are being suppressed, exit. */
|
|
if ((dsi->un_options & SD_SILENT) || (sf_debug == 0))
|
|
return;
|
|
|
|
/* Decode command name */
|
|
if (un->un_cmd < MAX_SF_CMDS) {
|
|
cmdname = sf_cmds[un->un_cmd];
|
|
} else {
|
|
cmdname = "unknown cmd";
|
|
}
|
|
|
|
/* If not a check condition error, block number is invalid */
|
|
if (! un->un_scb.chk)
|
|
blkno_flag = 0;
|
|
|
|
|
|
printf("sf%d%c: %s %s",
|
|
SFNUM(un), LPART(bp->b_dev) + 'a', cmdname, action);
|
|
if (blkno_flag)
|
|
printf(", block %d", dsi->un_err_blkno);
|
|
|
|
error_code = ssf->error_code;
|
|
printf("\n sense key(0x%x): %s",
|
|
ssf->key, sf_print_key(ssf->key));
|
|
if (error_code != 0) {
|
|
printf(", error code(0x%x): %s\n",
|
|
error_code, sf_print_error(dsi, error_code));
|
|
} else {
|
|
printf("\n");
|
|
}
|
|
|
|
}
|
|
#endif NSF > 0
|