diff options
-rw-r--r-- | sys/i386/i386/conf.c | 24 | ||||
-rw-r--r-- | sys/i386/isa/atapi.c | 284 | ||||
-rw-r--r-- | sys/i386/isa/atapi.h | 58 | ||||
-rw-r--r-- | sys/i386/isa/wcd.c | 435 | ||||
-rw-r--r-- | sys/i386/isa/wd.c | 54 | ||||
-rw-r--r-- | sys/pc98/pc98/atapi.h | 58 |
6 files changed, 703 insertions, 210 deletions
diff --git a/sys/i386/i386/conf.c b/sys/i386/i386/conf.c index 312b5f4..f2ca17f 100644 --- a/sys/i386/i386/conf.c +++ b/sys/i386/i386/conf.c @@ -42,7 +42,7 @@ * SUCH DAMAGE. * * from: @(#)conf.c 5.8 (Berkeley) 5/12/91 - * $Id: conf.c,v 1.100 1995/10/12 23:28:41 bde Exp $ + * $Id: conf.c,v 1.101 1995/10/14 05:25:45 bde Exp $ */ #include <sys/param.h> @@ -305,13 +305,17 @@ d_psize_t atasize; #include "wcd.h" #if NWCD > 0 -d_open_t wcdopen; -d_close_t wcdclose; +d_open_t wcdbopen; +d_open_t wcdropen; +d_close_t wcdbclose; +d_close_t wcdrclose; d_strategy_t wcdstrategy; d_ioctl_t wcdioctl; #else -#define wcdopen nxopen -#define wcdclose nxclose +#define wcdbopen nxopen +#define wcdropen nxopen +#define wcdbclose nxclose +#define wcdrclose nxclose #define wcdstrategy nxstrategy #define wcdioctl nxioctl #endif @@ -445,8 +449,8 @@ struct bdevsw bdevsw[] = matcddump, matcdsize, 0 }, { ataopen, ataclose, atastrategy, ataioctl, /*18*/ atadump, atasize, 0 }, - { wcdopen, wcdclose, wcdstrategy, wcdioctl, /*19*/ - nxdump, zerosize, 0 }, + { wcdbopen, wcdbclose, wcdstrategy, wcdioctl, /*19*/ + nxdump, zerosize, 0 }, { odopen, odclose, odstrategy, odioctl, /*20*/ oddump, odsize, 0 }, @@ -1291,9 +1295,9 @@ struct cdevsw cdevsw[] = { siopen, siclose, siread, siwrite, /*68*/ siioctl, sistop, sireset, sidevtotty,/* slxos */ ttselect, nxmmap, NULL }, - { wcdopen, wcdclose, rawread, nowrite, /*69*/ - wcdioctl, nostop, nullreset, nodevtotty,/* atapi */ - seltrue, nommap, wcdstrategy }, + { wcdropen, wcdrclose, rawread, nowrite, /*69*/ + wcdioctl, nostop, nullreset, nodevtotty,/* atapi */ + seltrue, nommap, wcdstrategy }, { odopen, odclose, rawread, rawwrite, /*70*/ odioctl, nostop, nullreset, nodevtotty,/* od */ seltrue, nommap, odstrategy }, diff --git a/sys/i386/isa/atapi.c b/sys/i386/isa/atapi.c index 540c2bd..6d608fb 100644 --- a/sys/i386/isa/atapi.c +++ b/sys/i386/isa/atapi.c @@ -11,7 +11,7 @@ * or modify this software as long as this message is kept with the software, * all derivative works or modified versions. * - * Version 1.5, Thu Sep 21 23:08:11 MSD 1995 + * Version 1.9, Mon Oct 9 22:34:47 MSK 1995 */ /* @@ -112,16 +112,40 @@ #include <sys/malloc.h> #include <i386/include/cpufunc.h> #include <i386/include/clock.h> + +#ifdef ATAPI_MODULE +# define ATAPI_STATIC +#endif + #include <i386/isa/atapi.h> +#ifndef ATAPI_STATIC +/* + * In the case of loadable ATAPI driver we need to store + * the probe info for delayed attaching. + */ +struct atapidrv atapi_drvtab[4]; +int atapi_ndrv; +struct atapi *atapi_tab; + +int atapi_attach (int ctlr, int unit, int port, struct kern_devconf *parent) +{ + atapi_drvtab[atapi_ndrv].ctlr = ctlr; + atapi_drvtab[atapi_ndrv].unit = unit; + atapi_drvtab[atapi_ndrv].port = port; + atapi_drvtab[atapi_ndrv].parent = parent; + atapi_drvtab[atapi_ndrv].attached = 0; + ++atapi_ndrv; + return (1); +} +#else /* ATAPI_STATIC */ + #ifdef DEBUG # define print(s) printf s #else # define print(s) {/*void*/} #endif -#define MAXCMD (8*NWDC) - /* * ATAPI packet command phase. */ @@ -131,32 +155,6 @@ #define PHASE_COMPLETED (ARI_IN | ARI_CMD) #define PHASE_ABORTED 0 /* nonstandard - for NEC 260 */ -struct atapicmd { /* ATAPI command block */ - struct atapicmd *next; /* next command in queue */ - int busy; /* busy flag */ - u_char cmd[16]; /* command and args */ - int unit; /* drive unit number */ - int count; /* byte count, >0 - read, <0 - write */ - char *addr; /* data to transfer */ - void (*callback) (); /* call when done */ - void *cbarg1; /* callback arg 1 */ - void *cbarg2; /* callback arg 1 */ - struct atapires result; /* resulting error code */ -}; - -struct atapi { /* ATAPI controller data */ - u_short port; /* i/o port base */ - u_char ctrlr; /* physical controller number */ - u_char debug : 1; /* trace enable flag */ - u_char cmd16 : 1; /* 16-byte command flag */ - u_char intrcmd : 1; /* interrupt before cmd flag */ - u_char slow : 1; /* slow reaction device */ - struct atapicmd *queue; /* queue of commands to perform */ - struct atapicmd *tail; /* tail of queue */ - struct atapicmd *free; /* queue of free command blocks */ - struct atapicmd cmdrq[MAXCMD]; /* pool of command requests */ -}; - struct atapi atapitab[NWDC]; static struct atapi_params *atapi_probe (int port, int unit); @@ -167,8 +165,16 @@ static int atapi_start_cmd (struct atapi *ata, struct atapicmd *ac); static int atapi_wait_cmd (struct atapi *ata, struct atapicmd *ac); extern int wdstart (int ctrlr); +extern int wcdattach(struct atapi*, int, struct atapi_params*, int, struct kern_devconf*); -void atapi_attach (int ctlr, int unit, int port, struct kern_devconf *parent) +/* + * Probe the ATAPI device at IDE controller `ctlr', drive `unit'. + * Called at splbio(). + */ +#ifdef ATAPI_MODULE +static +#endif +int atapi_attach (int ctlr, int unit, int port, struct kern_devconf *parent) { struct atapi *ata = atapitab + ctlr; struct atapi_params *ap; @@ -179,7 +185,7 @@ void atapi_attach (int ctlr, int unit, int port, struct kern_devconf *parent) print (("atapi%d.%d at 0x%x: attach called\n", ctlr, unit, port)); ap = atapi_probe (port, unit); if (! ap) - return; + return (0); bcopy (ap->model, buf, sizeof(buf)-1); buf[sizeof(buf)-1] = 0; @@ -230,14 +236,16 @@ void atapi_attach (int ctlr, int unit, int port, struct kern_devconf *parent) ata->port = port; ata->ctrlr = ctlr; + ata->parent = parent; + ata->attached[unit] = 0; #ifdef DEBUG ata->debug = 1; #else ata->debug = 0; #endif /* Initialize free queue. */ - ata->cmdrq[MAXCMD-1].next = 0; - for (ac = ata->cmdrq+MAXCMD-2; ac >= ata->cmdrq; --ac) + ata->cmdrq[15].next = 0; + for (ac = ata->cmdrq+14; ac >= ata->cmdrq; --ac) ac->next = ac+1; ata->free = ata->cmdrq; @@ -245,8 +253,12 @@ void atapi_attach (int ctlr, int unit, int port, struct kern_devconf *parent) printf ("wdc%d: unit %d: unknown ATAPI protocol=%d\n", ctlr, unit, ap->proto); free (ap, M_TEMP); - return; + return (0); } +#ifdef ATAPI_MODULE + ata->params[unit] = ap; + return (1); +#else switch (ap->devtype) { default: /* unknown ATAPI device */ @@ -258,14 +270,11 @@ void atapi_attach (int ctlr, int unit, int port, struct kern_devconf *parent) case AT_TYPE_CDROM: /* CD-ROM device */ #if NWCD > 0 /* ATAPI CD-ROM */ - { - int wcdattach (struct atapi*, int, struct atapi_params*, - int, struct kern_devconf*); - if (wcdattach (ata, unit, ap, ata->debug, parent) < 0) - break; - } + if (wcdattach (ata, unit, ap, ata->debug, parent) < 0) + break; /* Device attached successfully. */ - return; + ata->attached[unit] = 1; + return (1); #else printf ("wdc%d: ATAPI CD-ROMs not configured\n", ctlr); break; @@ -276,19 +285,46 @@ void atapi_attach (int ctlr, int unit, int port, struct kern_devconf *parent) /* Add your driver here */ #else printf ("wdc%d: ATAPI streaming tapes not supported yet\n", ctlr); - break; #endif + break; case AT_TYPE_OPTICAL: /* optical disk */ #if NWMD > 0 /* Add your driver here */ #else printf ("wdc%d: ATAPI optical disks not supported yet\n", ctlr); - break; #endif + break; } /* Attach failed. */ free (ap, M_TEMP); + return (0); +#endif /* ATAPI_MODULE */ +} + +static char *cmdname (u_char cmd) +{ + static char buf[8]; + + switch (cmd) { + case 0x00: return ("TEST_UNIT_READY"); + case 0x03: return ("REQUEST_SENSE"); + case 0x1b: return ("START_STOP"); + case 0x1e: return ("PREVENT_ALLOW"); + case 0x25: return ("READ_CAPACITY"); + case 0x28: return ("READ_BIG"); + case 0x43: return ("READ_TOC"); + case 0x42: return ("READ_SUBCHANNEL"); + case 0x55: return ("MODE_SELECT_BIG"); + case 0x5a: return ("MODE_SENSE"); + case 0xb4: return ("PLAY_CD"); + case 0x47: return ("PLAY_MSF"); + case 0x4b: return ("PAUSE"); + case 0x48: return ("PLAY_TRACK"); + case 0xa5: return ("PLAY_BIG"); + } + sprintf (buf, "[0x%x]", cmd); + return (buf); } static void bswap (char *buf, int len) @@ -319,6 +355,7 @@ static struct atapi_params *atapi_probe (int port, int unit) char tb [DEV_BSIZE]; /* Wait for controller not busy. */ + outb (port + AR_DRIVE, unit ? ARD_DRIVE1 : ARD_DRIVE0); if (atapi_wait (port, 0) < 0) { print (("atapiX.%d at 0x%x: controller busy, status=%b\n", unit, port, inb (port + AR_STATUS), ARS_BITS)); @@ -361,11 +398,10 @@ static struct atapi_params *atapi_probe (int port, int unit) * Mitsumi and NEC drives don't need this. */ if (! ((ap->model[0] == 'N' && ap->model[1] == 'E') || - (ap->model[0] == 'F' && ap->model[1] == 'X'))) { + (ap->model[0] == 'F' && ap->model[1] == 'X'))) bswap (ap->model, sizeof(ap->model)); - bswap (ap->serial, sizeof(ap->serial)); - bswap (ap->revision, sizeof(ap->revision)); - } + bswap (ap->serial, sizeof(ap->serial)); + bswap (ap->revision, sizeof(ap->revision)); /* Clean up the model name, serial and revision numbers. */ btrim (ap->model, sizeof(ap->model)); @@ -537,17 +573,26 @@ int atapi_wait_cmd (struct atapi *ata, struct atapicmd *ac) { /* Wait for DRQ from 50 usec to 3 msec for slow devices */ int cnt = ata->intrcmd ? 10000 : ata->slow ? 3000 : 50; + int ireason = 0, phase = 0; + /* Wait for command phase. */ for (; cnt>0; cnt-=10) { + ireason = inb (ata->port + AR_IREASON); ac->result.status = inb (ata->port + AR_STATUS); - if (ac->result.status & ARS_DRQ) + phase = (ireason & (ARI_CMD | ARI_IN)) | + (ac->result.status & ARS_DRQ); + if (phase == PHASE_CMDOUT) break; DELAY (10); } - if (! (ac->result.status & ARS_DRQ)) { - printf ("atapi%d.%d: no cmd drq\n", ata->ctrlr, ac->unit); + + if (phase != PHASE_CMDOUT) { ac->result.code = RES_NODRQ; ac->result.error = inb (ata->port + AR_ERROR); + printf ("atapi%d.%d: invalid command phase, ireason=0x%x, status=%b, error=%b\n", + ata->ctrlr, ac->unit, ireason, + ac->result.status, ARS_BITS, + ac->result.error, AER_BITS); return (-1); } return (0); @@ -560,11 +605,11 @@ void atapi_send_cmd (struct atapi *ata, struct atapicmd *ac) { outsw (ata->port + AR_DATA, ac->cmd, ata->cmd16 ? 8 : 6); if (ata->debug) - printf ("atapi%d.%d: send cmd %x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x\n", - ata->ctrlr, ac->unit, ac->cmd[0], ac->cmd[1], - ac->cmd[2], ac->cmd[3], ac->cmd[4], ac->cmd[5], - ac->cmd[6], ac->cmd[7], ac->cmd[8], ac->cmd[9], - ac->cmd[10], ac->cmd[11], ac->cmd[12], + printf ("atapi%d.%d: send cmd %s %x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x\n", + ata->ctrlr, ac->unit, cmdname (ac->cmd[0]), ac->cmd[0], + ac->cmd[1], ac->cmd[2], ac->cmd[3], ac->cmd[4], + ac->cmd[5], ac->cmd[6], ac->cmd[7], ac->cmd[8], + ac->cmd[9], ac->cmd[10], ac->cmd[11], ac->cmd[12], ac->cmd[13], ac->cmd[14], ac->cmd[15]); } @@ -853,4 +898,133 @@ struct atapires atapi_request_immediate (struct atapi *ata, int unit, } return (ac->result); } +#endif /* ATAPI_STATIC */ + +#ifdef ATAPI_MODULE +/* + * ATAPI loadable driver stubs. + */ +#include <sys/exec.h> +#include <sys/conf.h> +#include <sys/sysent.h> +#include <sys/lkm.h> + +extern int (*atapi_start_ptr) (int ctrlr); +extern int (*atapi_intr_ptr) (int ctrlr); +extern void (*atapi_debug_ptr) (struct atapi *ata, int on); +extern struct atapires (*atapi_request_wait_ptr) (struct atapi *ata, int unit, + u_char cmd, u_char a1, u_char a2, u_char a3, u_char a4, + u_char a5, u_char a6, u_char a7, u_char a8, u_char a9, + u_char a10, u_char a11, u_char a12, u_char a13, u_char a14, u_char a15, + char *addr, int count); +extern void (*atapi_request_callback_ptr) (struct atapi *ata, int unit, + u_char cmd, u_char a1, u_char a2, u_char a3, u_char a4, + u_char a5, u_char a6, u_char a7, u_char a8, u_char a9, + u_char a10, u_char a11, u_char a12, u_char a13, u_char a14, u_char a15, + char *addr, int count, void (*done)(), void *x, void *y); +extern struct atapires (*atapi_request_immediate_ptr) (struct atapi *ata, int unit, + u_char cmd, u_char a1, u_char a2, u_char a3, u_char a4, + u_char a5, u_char a6, u_char a7, u_char a8, u_char a9, + u_char a10, u_char a11, u_char a12, u_char a13, u_char a14, u_char a15, + char *addr, int count); + +extern void wdintr (int); + +/* + * Construct lkm_misc structure (see lkm.h). + */ +MOD_MISC("atapi") + +int atapi_locked; + +int atapi_lock (int ctlr) +{ + atapi_locked = 1; + wakeup (&atapi_locked); + return (1); +} + +/* + * Function called when loading the driver. + */ +int atapi_load (struct lkm_table *lkmtp, int cmd) +{ + struct atapidrv *d; + int n, x; + + /* + * Probe all free IDE units, searching for ATAPI drives. + */ + n = 0; + for (d=atapi_drvtab; d<atapi_drvtab+atapi_ndrv && d->port; ++d) { + /* Lock the controller. */ + x = splbio (); + atapi_locked = 0; + atapi_start_ptr = atapi_lock; + wdstart (d->ctlr); + while (! atapi_locked) + tsleep (&atapi_locked, PRIBIO, "atach", 0); + + /* Probe the drive. */ + if (atapi_attach (d->ctlr, d->unit, d->port, d->parent)) { + d->attached = 1; + ++n; + } + + /* Unlock the controller. */ + atapi_start_ptr = 0; + wdintr (d->ctlr); + splx (x); + } + if (! n) + return ENXIO; + atapi_start_ptr = atapi_start; + atapi_intr_ptr = atapi_intr; + atapi_debug_ptr = atapi_debug; + atapi_request_wait_ptr = atapi_request_wait; + atapi_request_callback_ptr = atapi_request_callback; + atapi_request_immediate_ptr = atapi_request_immediate; + atapi_tab = atapitab; + return 0; +} + +/* + * Function called when unloading the driver. + */ +int atapi_unload (struct lkm_table *lkmtp, int cmd) +{ + struct atapi *ata; + int u; + + for (ata=atapi_tab; ata<atapi_tab+2; ++ata) + if (ata->port) + for (u=0; u<2; ++u) + if (ata->attached[u]) + return EBUSY; + for (ata=atapi_tab; ata<atapi_tab+2; ++ata) + if (ata->port) + for (u=0; u<2; ++u) + if (ata->params[u]) { + free (ata->params[u], M_TEMP); + ata->params[u] = 0; + } + atapi_start_ptr = 0; + atapi_intr_ptr = 0; + atapi_debug_ptr = 0; + atapi_request_wait_ptr = 0; + atapi_request_callback_ptr = 0; + atapi_request_immediate_ptr = 0; + atapi_tab = 0; + return 0; +} + +/* + * Dispatcher function for the module (load/unload/stat). + */ +int atapi (struct lkm_table *lkmtp, int cmd, int ver) +{ + DISPATCH (lkmtp, cmd, ver, atapi_load, atapi_unload, nosys); +} +#endif /* ATAPI_MODULE */ + #endif /* NWDC && ATAPI */ diff --git a/sys/i386/isa/atapi.h b/sys/i386/isa/atapi.h index cb46dcc..f22a5a2 100644 --- a/sys/i386/isa/atapi.h +++ b/sys/i386/isa/atapi.h @@ -11,7 +11,7 @@ * or modify this software as long as this message is kept with the software, * all derivative works or modified versions. * - * Version 1.8, Thu Sep 28 20:24:38 MSK 1995 + * Version 1.9, Thu Oct 12 15:53:50 MSK 1995 */ /* @@ -190,10 +190,64 @@ struct atapires { u_char error; /* error register contents */ }; +struct atapidrv { /* delayed attach info */ + int ctlr; /* IDE controller, 0/1 */ + int unit; /* drive unit, 0/1 */ + int port; /* controller base port */ + int attached; /* the drive is attached */ + struct kern_devconf *parent; /* the devconf info pattern */ +}; + +struct atapicmd { /* ATAPI command block */ + struct atapicmd *next; /* next command in queue */ + int busy; /* busy flag */ + u_char cmd[16]; /* command and args */ + int unit; /* drive unit number */ + int count; /* byte count, >0 - read, <0 - write */ + char *addr; /* data to transfer */ + void (*callback) (); /* call when done */ + void *cbarg1; /* callback arg 1 */ + void *cbarg2; /* callback arg 1 */ + struct atapires result; /* resulting error code */ +}; + +struct atapi { /* ATAPI controller data */ + u_short port; /* i/o port base */ + u_char ctrlr; /* physical controller number */ + u_char debug : 1; /* trace enable flag */ + u_char cmd16 : 1; /* 16-byte command flag */ + u_char intrcmd : 1; /* interrupt before cmd flag */ + u_char slow : 1; /* slow reaction device */ + u_char attached[2]; /* units are attached to subdrivers */ + struct atapi_params *params[2]; /* params for units 0,1 */ + struct kern_devconf *parent; /* parent configuration pattern */ + struct atapicmd *queue; /* queue of commands to perform */ + struct atapicmd *tail; /* tail of queue */ + struct atapicmd *free; /* queue of free command blocks */ + struct atapicmd cmdrq[16]; /* pool of command requests */ +}; + #ifdef KERNEL struct atapi; struct kern_devconf; -void atapi_attach (int ctlr, int unit, int port, struct kern_devconf*); + +extern struct atapidrv atapi_drvtab[4]; /* delayed attach info */ +extern int atapi_ndrv; /* the number of potential drives */ +extern struct atapi *atapi_tab; /* the table of atapi controllers */ + +#ifndef ATAPI_STATIC +# define atapi_start (*atapi_start_ptr) +# define atapi_intr (*atapi_intr_ptr) +# define atapi_debug (*atapi_debug_ptr) +# define atapi_request_wait (*atapi_request_wait_ptr) +# define atapi_request_callback (*atapi_request_callback_ptr) +# define atapi_request_immediate (*atapi_request_immediate_ptr) +#endif + +#ifndef ATAPI_MODULE +int atapi_attach (int ctlr, int unit, int port, struct kern_devconf*); +#endif + int atapi_start (int ctrlr); int atapi_intr (int ctrlr); void atapi_debug (struct atapi *ata, int on); diff --git a/sys/i386/isa/wcd.c b/sys/i386/isa/wcd.c index a5a2dff..a64953a 100644 --- a/sys/i386/isa/wcd.c +++ b/sys/i386/isa/wcd.c @@ -12,7 +12,7 @@ * or modify this software as long as this message is kept with the software, * all derivative works or modified versions. * - * Version 1.8, Thu Sep 28 21:04:16 MSK 1995 + * Version 1.9, Mon Oct 9 20:27:42 MSK 1995 */ #include "wdc.h" @@ -36,10 +36,9 @@ #define UNIT(d) ((minor(d) >> 3) & 3) /* Unit part of minor device number */ #define SECSIZE 2048 /* CD-ROM sector size in bytes */ -#define F_OPEN 0x0001 /* The drive os opened */ +#define F_BOPEN 0x0001 /* The block device is opened */ #define F_MEDIA_CHANGED 0x0002 /* The media have changed since open */ -#define F_DEBUG 0x0004 /* The media have changed since open */ -#define F_NOPLAYCD 0x0008 /* The PLAY_CD op not supported */ +#define F_DEBUG 0x0004 /* Print debug info */ /* * Disc table of contents. @@ -184,6 +183,7 @@ struct wcd { int unit; /* IDE bus drive unit */ int lun; /* Logical device unit */ int flags; /* Device state flags */ + int refcnt; /* The number of raw opens */ struct buf queue; /* Queue of i/o requests */ struct atapi_params *param; /* Drive parameters table */ struct toc toc; /* Table of disc contents */ @@ -212,6 +212,7 @@ static int wcd_goaway (struct kern_devconf *kdc, int force); static void wcd_describe (struct wcd *t); static int wcd_setchan (struct wcd *t, u_char c0, u_char c1, u_char c2, u_char c3); +static int wcd_eject (struct wcd *t); static struct kern_devconf cftemplate = { 0, 0, 0, "wcd", 0, { MDDT_DISK, 0 }, @@ -244,7 +245,7 @@ static int wcd_goaway (struct kern_devconf *kdc, int force) return 0; } -void wcdattach (struct atapi *ata, int unit, struct atapi_params *ap, int debug, +int wcdattach (struct atapi *ata, int unit, struct atapi_params *ap, int debug, struct kern_devconf *parent) { struct wcd *t; @@ -252,12 +253,12 @@ void wcdattach (struct atapi *ata, int unit, struct atapi_params *ap, int debug, if (wcdnlun >= NUNIT) { printf ("wcd: too many units\n"); - return; + return (0); } t = malloc (sizeof (struct wcd), M_TEMP, M_NOWAIT); if (! t) { printf ("wcd: out of memory\n"); - return; + return (0); } wcdtab[wcdnlun] = t; bzero (t, sizeof (struct wcd)); @@ -266,6 +267,7 @@ void wcdattach (struct atapi *ata, int unit, struct atapi_params *ap, int debug, t->lun = wcdnlun++; t->param = ap; t->flags = F_MEDIA_CHANGED; + t->refcnt = 0; if (debug) { t->flags |= F_DEBUG; /* Print params. */ @@ -305,6 +307,7 @@ void wcdattach (struct atapi *ata, int unit, struct atapi_params *ap, int debug, strncpy (t->description + strlen(t->description), ap->model, sizeof(ap->model)); dev_attach (&t->cf); + return (1); } void wcd_describe (struct wcd *t) @@ -365,89 +368,72 @@ void wcd_describe (struct wcd *t) printf ("\n"); } -int wcdopen (dev_t dev, int flags, int fmt, struct proc *p) +int wcd_open (dev_t dev, int rawflag) { int lun = UNIT(dev); struct wcd *t; struct atapires result; - /* Check the unit is legal. */ - if (lun >= wcdnlun) + /* Check that the device number is legal + * and the ATAPI driver is loaded. */ + if (lun >= wcdnlun || ! atapi_request_immediate) return (ENXIO); t = wcdtab[lun]; - /* If already opened, that's all. */ - if (t->flags & F_OPEN) { - /* If it's been invalidated, forbid re-entry. - * (may have changed media) */ - if (t->flags & F_MEDIA_CHANGED) - return (ENXIO); - return (0); - } - - /* On the first open: check for the media. - * Do it twice to avoid the stale media changed state. */ - result = atapi_request_wait (t->ata, t->unit, ATAPI_TEST_UNIT_READY, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + /* On the first open, read the table of contents. */ + if (! (t->flags & F_BOPEN) && ! t->refcnt) { + /* Read table of contents. */ + if (wcd_read_toc (t) < 0) + return (EIO); - if (result.code == RES_ERR && - (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION) { - t->flags |= F_MEDIA_CHANGED; - result = atapi_request_wait (t->ata, t->unit, - ATAPI_TEST_UNIT_READY, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0); - } - if (result.code) { - wcd_error (t, result); - return (ENXIO); + /* Lock the media. */ + wcd_request_wait (t, ATAPI_PREVENT_ALLOW, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0); } + if (rawflag) + ++t->refcnt; + else + t->flags |= F_BOPEN; + return (0); +} - /* Read table of contents. */ - if (wcd_read_toc (t) != 0) - bzero (&t->toc, sizeof (t->toc)); - - /* Read disc capacity. */ - if (wcd_request_wait (t, ATAPI_READ_CAPACITY, 0, 0, 0, 0, 0, 0, - 0, sizeof(t->info), 0, (char*)&t->info, sizeof(t->info)) != 0) - bzero (&t->info, sizeof (t->info)); - t->info.volsize = ntohl (t->info.volsize); - t->info.blksize = ntohl (t->info.blksize); - - /* Print the disc description string on every disc change. - * It would help to track the history of disc changes. */ - if (t->info.volsize && t->toc.hdr.ending_track && - (t->flags & F_MEDIA_CHANGED) && (t->flags & F_DEBUG)) { - printf ("wcd%d: ", t->lun); - if (t->toc.tab[0].control & 4) - printf ("%ldMB ", t->info.volsize / 512); - else - printf ("%ld:%ld audio ", t->info.volsize/75/60, - t->info.volsize/75%60); - printf ("(%ld sectors), %d tracks\n", t->info.volsize, - t->toc.hdr.ending_track - t->toc.hdr.starting_track + 1); - } - /* Lock the media. */ - wcd_request_wait (t, ATAPI_PREVENT_ALLOW, - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0); +int wcdbopen (dev_t dev, int flags, int fmt, struct proc *p) +{ + return wcd_open (dev, 0); +} - t->flags &= ~F_MEDIA_CHANGED; - t->flags |= F_OPEN; - return (0); +int wcdropen (dev_t dev, int flags, int fmt, struct proc *p) +{ + return wcd_open (dev, 1); } /* * Close the device. Only called if we are the LAST * occurence of an open device. */ -int wcdclose (dev_t dev, int flags, int fmt, struct proc *p) +int wcdbclose (dev_t dev, int flags, int fmt, struct proc *p) { int lun = UNIT(dev); struct wcd *t = wcdtab[lun]; /* If we were the last open of the entire device, release it. */ - wcd_request_wait (t, ATAPI_PREVENT_ALLOW, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - t->flags &= ~F_OPEN; + if (! t->refcnt) + wcd_request_wait (t, ATAPI_PREVENT_ALLOW, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + t->flags &= ~F_BOPEN; + return (0); +} + +int wcdrclose (dev_t dev, int flags, int fmt, struct proc *p) +{ + int lun = UNIT(dev); + struct wcd *t = wcdtab[lun]; + + /* If we were the last open of the entire device, release it. */ + if (! (t->flags & F_BOPEN) && t->refcnt == 1) + wcd_request_wait (t, ATAPI_PREVENT_ALLOW, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + --t->refcnt; return (0); } @@ -462,15 +448,6 @@ void wcdstrategy (struct buf *bp) struct wcd *t = wcdtab[lun]; int x; - /* If the device has been made invalid, error out - * maybe the media changed. */ - if (t->flags & F_MEDIA_CHANGED) { - bp->b_error = EIO; - bp->b_flags |= B_ERROR; - biodone (bp); - return; - } - /* Can't ever write to a CD. */ if (! (bp->b_flags & B_READ)) { bp->b_error = EROFS; @@ -608,34 +585,6 @@ static int wcd_request_wait (struct wcd *t, u_char cmd, u_char a1, u_char a2, return (0); } -static int wcd_play (struct wcd *t, u_char cmd, u_char a1, u_char a2, - u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8, - u_char a9, char *addr, int count) -{ - struct atapires result; - - if (! (t->flags & F_NOPLAYCD)) { - t->cf.kdc_state = DC_BUSY; - result = atapi_request_wait (t->ata, t->unit, ATAPI_PLAY_CD, - cmd == ATAPI_PLAY_MSF ? 2 : 0, a2, a3, a4, a5, a6, - a7, a8, a9, 0, 0, 0, 0, 0, 0, addr, count); - t->cf.kdc_state = DC_IDLE; - if (result.code == RES_ERR && - (result.error & AER_SKEY) == AER_SK_ILLEGAL_REQUEST) { - /* Some drives don't support a PLAY_CD command. - * Remember this and use PLAY_MSF instead. */ - t->flags |= F_NOPLAYCD; - result.code = 0; - } - if (result.code) { - wcd_error (t, result); - return (EIO); - } - } - return wcd_request_wait (t, cmd, a1, a2, a3, a4, a5, a6, - a7, a8, a9, addr, count); -} - static inline void lba2msf (int lba, u_char *m, u_char *s, u_char *f) { lba += 150; /* offset of first logical frame */ @@ -650,15 +599,29 @@ static inline void lba2msf (int lba, u_char *m, u_char *s, u_char *f) * Perform special action on behalf of the user. * Knows about the internals of this device */ -int wcdioctl (dev_t dev, int cmd, caddr_t addr, int flags, struct proc *p) +int wcdioctl (dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p) { int lun = UNIT(dev); struct wcd *t = wcdtab[lun]; + struct atapires result; int error = 0; - /* If the device is not valid.. abandon ship. */ if (t->flags & F_MEDIA_CHANGED) - return (EIO); + switch (cmd) { + case CDIOCSETDEBUG: + case CDIOCCLRDEBUG: + case CDIOCRESET: + /* These ops are media change transparent. */ + break; + default: + /* Read table of contents. */ + wcd_read_toc (t); + + /* Lock the media. */ + wcd_request_wait (t, ATAPI_PREVENT_ALLOW, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0); + break; + } switch (cmd) { default: return (ENOTTY); @@ -708,21 +671,15 @@ int wcdioctl (dev_t dev, int cmd, caddr_t addr, int flags, struct proc *p) 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); case CDIOCEJECT: - /* Stop the disc. */ - error = wcd_request_wait (t, ATAPI_START_STOP, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - if (error) - return (error); - /* Give it some time to stop spinning. */ - tsleep ((caddr_t)&lbolt, PRIBIO, "wcdejct", 0); - tsleep ((caddr_t)&lbolt, PRIBIO, "wcdejct", 0); - /* Eject. */ - return wcd_request_wait (t, ATAPI_START_STOP, - 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0); + /* Don't allow eject if the device is opened + * by somebody (not us) in block mode. */ + if ((t->flags & F_BOPEN) && t->refcnt) + return (EBUSY); + return wcd_eject (t); case CDIOREADTOCHEADER: if (! t->toc.hdr.ending_track) - return (ENODEV); + return (EIO); bcopy (&t->toc.hdr, addr, sizeof t->toc.hdr); break; @@ -734,7 +691,7 @@ int wcdioctl (dev_t dev, int cmd, caddr_t addr, int flags, struct proc *p) u_long len; if (! t->toc.hdr.ending_track) - return (ENODEV); + return (EIO); if (te->starting_track < toc->hdr.starting_track || te->starting_track > toc->hdr.ending_track) return (EINVAL); @@ -808,14 +765,14 @@ int wcdioctl (dev_t dev, int cmd, caddr_t addr, int flags, struct proc *p) case CDIOCPLAYMSF: { struct ioc_play_msf *args = (struct ioc_play_msf*) addr; - return wcd_play (t, ATAPI_PLAY_MSF, 0, 0, + return wcd_request_wait (t, ATAPI_PLAY_MSF, 0, 0, args->start_m, args->start_s, args->start_f, args->end_m, args->end_s, args->end_f, 0, 0, 0); } case CDIOCPLAYBLOCKS: { struct ioc_play_blocks *args = (struct ioc_play_blocks*) addr; - return wcd_play (t, ATAPI_PLAY_BIG, 0, + return wcd_request_wait (t, ATAPI_PLAY_BIG, 0, args->blk >> 24 & 0xff, args->blk >> 16 & 0xff, args->blk >> 8 & 0xff, args->blk & 0xff, args->len >> 24 & 0xff, args->len >> 16 & 0xff, @@ -827,7 +784,7 @@ int wcdioctl (dev_t dev, int cmd, caddr_t addr, int flags, struct proc *p) int t1, t2; if (! t->toc.hdr.ending_track) - return (ENODEV); + return (EIO); /* Ignore index fields, * play from start_track to end_track inclusive. */ @@ -842,7 +799,7 @@ int wcdioctl (dev_t dev, int cmd, caddr_t addr, int flags, struct proc *p) start = t->toc.tab[t1].addr.lba; len = t->toc.tab[t2].addr.lba - start; - return wcd_play (t, ATAPI_PLAY_BIG, 0, + return wcd_request_wait (t, ATAPI_PLAY_BIG, 0, start >> 24 & 0xff, start >> 16 & 0xff, start >> 8 & 0xff, start & 0xff, len >> 24 & 0xff, len >> 16 & 0xff, @@ -888,6 +845,9 @@ int wcdioctl (dev_t dev, int cmd, caddr_t addr, int flags, struct proc *p) if (t->flags & F_DEBUG) wcd_dump (t->lun, "mask", &t->aumask, sizeof t->aumask); + /* Sony-55E requires the data length field to be zeroed. */ + t->au.data_length = 0; + t->au.port[0].channels = CHANNEL_0; t->au.port[1].channels = CHANNEL_1; t->au.port[0].volume = arg->vol[0] & t->aumask.port[0].volume; @@ -929,16 +889,40 @@ int wcdioctl (dev_t dev, int cmd, caddr_t addr, int flags, struct proc *p) static int wcd_read_toc (struct wcd *t) { int ntracks, len, i; + struct atapires result; + + bzero (&t->toc, sizeof (t->toc)); + bzero (&t->info, sizeof (t->info)); + + /* Check for the media. + * Do it twice to avoid the stale media changed state. */ + result = atapi_request_wait (t->ata, t->unit, ATAPI_TEST_UNIT_READY, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + + if (result.code == RES_ERR && + (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION) { + t->flags |= F_MEDIA_CHANGED; + result = atapi_request_wait (t->ata, t->unit, + ATAPI_TEST_UNIT_READY, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0); + } + if (result.code) { + wcd_error (t, result); + return (EIO); + } + t->flags &= ~F_MEDIA_CHANGED; /* First read just the header, so we know how long the TOC is. */ len = sizeof(struct ioc_toc_header) + sizeof(struct cd_toc_entry); if (wcd_request_wait (t, ATAPI_READ_TOC, 0, 0, 0, 0, 0, 0, - len >> 8, len & 0xff, 0, (char*)&t->toc, len) != 0) - return (EIO); + len >> 8, len & 0xff, 0, (char*)&t->toc, len) != 0) { +err: bzero (&t->toc, sizeof (t->toc)); + return (0); + } ntracks = t->toc.hdr.ending_track - t->toc.hdr.starting_track + 1; if (ntracks <= 0) - return (EIO); + goto err; if (ntracks > MAXTRK) ntracks = MAXTRK; @@ -947,11 +931,36 @@ static int wcd_read_toc (struct wcd *t) (ntracks+1) * sizeof(struct cd_toc_entry); if (wcd_request_wait (t, ATAPI_READ_TOC, 0, 0, 0, 0, 0, 0, len >> 8, len & 0xff, 0, (char*)&t->toc, len) & 0xff) - return (EIO); + goto err; t->toc.hdr.len = ntohs (t->toc.hdr.len); for (i=0; i<=ntracks; i++) t->toc.tab[i].addr.lba = ntohl (t->toc.tab[i].addr.lba); + + /* Decrement the total length of the disc. + * Some drives (e.g. Sony-55E) have this value too big. */ + --t->toc.tab[ntracks].addr.lba; + + /* Read disc capacity. */ + if (wcd_request_wait (t, ATAPI_READ_CAPACITY, 0, 0, 0, 0, 0, 0, + 0, sizeof(t->info), 0, (char*)&t->info, sizeof(t->info)) != 0) + bzero (&t->info, sizeof (t->info)); + t->info.volsize = ntohl (t->info.volsize); + t->info.blksize = ntohl (t->info.blksize); + + /* Print the disc description string on every disc change. + * It would help to track the history of disc changes. */ + if (t->info.volsize && t->toc.hdr.ending_track && + (t->flags & F_MEDIA_CHANGED) && (t->flags & F_DEBUG)) { + printf ("wcd%d: ", t->lun); + if (t->toc.tab[0].control & 4) + printf ("%ldMB ", t->info.volsize / 512); + else + printf ("%ld:%ld audio ", t->info.volsize/75/60, + t->info.volsize/75%60); + printf ("(%ld sectors), %d tracks\n", t->info.volsize, + t->toc.hdr.ending_track - t->toc.hdr.starting_track + 1); + } return (0); } @@ -973,6 +982,9 @@ static int wcd_setchan (struct wcd *t, if (t->au.page_code != AUDIO_PAGE) return (EIO); + /* Sony-55E requires the data length field to be zeroed. */ + t->au.data_length = 0; + t->au.port[0].channels = c0; t->au.port[1].channels = c1; t->au.port[2].channels = c2; @@ -981,4 +993,171 @@ static int wcd_setchan (struct wcd *t, 0, 0, 0, 0, 0, sizeof (t->au) >> 8, sizeof (t->au), 0, (char*) &t->au, - sizeof (t->au)); } + +static int wcd_eject (struct wcd *t) +{ + struct atapires result; + + /* Try to stop the disc. */ + t->cf.kdc_state = DC_BUSY; + result = atapi_request_wait (t->ata, t->unit, ATAPI_START_STOP, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + t->cf.kdc_state = DC_IDLE; + + if (result.code == RES_ERR && + ((result.error & AER_SKEY) == AER_SK_NOT_READY || + (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)) { + /* + * The disc was unloaded. + * Load it (close tray). + * Read the table of contents. + */ + int err = wcd_request_wait (t, ATAPI_START_STOP, + 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0); + if (err) + return (err); + + /* Read table of contents. */ + wcd_read_toc (t); + + /* Lock the media. */ + wcd_request_wait (t, ATAPI_PREVENT_ALLOW, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0); + + return (0); + } + + if (result.code) { + wcd_error (t, result); + return (EIO); + } + + /* Give it some time to stop spinning. */ + tsleep ((caddr_t)&lbolt, PRIBIO, "wcdej1", 0); + tsleep ((caddr_t)&lbolt, PRIBIO, "wcdej2", 0); + + /* Unlock. */ + wcd_request_wait (t, ATAPI_PREVENT_ALLOW, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + + /* Eject. */ + t->flags |= F_MEDIA_CHANGED; + return wcd_request_wait (t, ATAPI_START_STOP, + 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0); +} + +#ifdef WCD_MODULE +/* + * Loadable ATAPI CD-ROM driver stubs. + */ +#include <sys/exec.h> +#include <sys/sysent.h> +#include <sys/lkm.h> + +/* + * Device table entries. + * These get copied at modload time into the kernels + * lkm dummy device driver entries (see sys/i386/i386/conf.c). + */ +#define NOSTOP (d_stop_t*) enodev +#define NOWRITE (d_rdwr_t*) enodev +#define NORESET (d_reset_t*) nullop +#define NODEVTOTTY (d_ttycv_t*) nullop +#define NOMMAP (d_mmap_t*) enodev +#define NODUMP (d_dump_t*) enxio +#define ZEROSIZE (d_psize_t*) 0 +d_rdwr_t rawread; +struct bdevsw dev_wcd = { wcdbopen, wcdbclose, wcdstrategy, wcdioctl, + NODUMP, ZEROSIZE, 0 }; +struct cdevsw dev_rwcd = { wcdropen, wcdrclose, rawread, NOWRITE, wcdioctl, + NOSTOP, NORESET, NODEVTOTTY, seltrue, NOMMAP, + wcdstrategy }; +/* + * Construct lkm_dev structures (see lkm.h). + * Our bdevsw/cdevsw slot numbers are 19/69. + */ +static struct lkm_dev wcd_module = { + LM_DEV, LKM_VERSION, "wcd", 19, LM_DT_BLOCK, { (void*) &dev_wcd } }; +static struct lkm_dev rwcd_module = { + LM_DEV, LKM_VERSION, "rwcd", 69, LM_DT_CHAR, { (void*) &dev_rwcd } }; + +/* + * Function called when loading the driver. + */ +int wcd_load (struct lkm_table *lkmtp, int cmd) +{ + struct atapi *ata; + int n, u; + + if (! atapi_start) + /* No ATAPI driver available. */ + return EPROTONOSUPPORT; + n = 0; + for (ata=atapi_tab; ata<atapi_tab+2; ++ata) + if (ata->port) + for (u=0; u<2; ++u) + /* Probing controller ata->ctrlr, unit u. */ + if (ata->params[u] && ! ata->attached[u] && + wcdattach (ata, u, ata->params[u], + ata->debug, ata->parent) >= 0) + { + /* Drive found. */ + ata->attached[u] = 1; + ++n; + } + if (! n) + /* No IDE CD-ROMs found. */ + return ENXIO; + return 0; +} + +/* + * Function called when unloading the driver. + */ +int wcd_unload (struct lkm_table *lkmtp, int cmd) +{ + struct wcd **t; + + for (t=wcdtab; t<wcdtab+wcdnlun; ++t) + if (((*t)->flags & F_BOPEN) || (*t)->refcnt) + /* The device is opened, cannot unload the driver. */ + return EBUSY; + for (t=wcdtab; t<wcdtab+wcdnlun; ++t) { + (*t)->ata->attached[(*t)->unit] = 0; + free (*t, M_TEMP); + } + wcdnlun = 0; + bzero (wcdtab, sizeof(wcdtab)); + return 0; +} + +/* + * Dispatcher function for the module (load/unload/stat). + */ +int wcd (struct lkm_table *lkmtp, int cmd, int ver) +{ + int err = 0; + + if (ver != LKM_VERSION) + return EINVAL; + + if (cmd == LKM_E_LOAD) + err = wcd_load (lkmtp, cmd); + else if (cmd == LKM_E_UNLOAD) + err = wcd_unload (lkmtp, cmd); + if (err) + return err; + + /* Register the cdevsw entry. */ + lkmtp->private.lkm_dev = &rwcd_module; + err = lkmdispatch (lkmtp, cmd); + if (err) + return err; + + /* Register the bdevsw entry. */ + lkmtp->private.lkm_dev = &wcd_module; + return lkmdispatch (lkmtp, cmd); +} +#endif /* WCD_MODULE */ + #endif /* NWCD && NWDC && ATAPI */ diff --git a/sys/i386/isa/wd.c b/sys/i386/isa/wd.c index 115f275..d3c8ec3 100644 --- a/sys/i386/isa/wd.c +++ b/sys/i386/isa/wd.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)wd.c 7.2 (Berkeley) 5/9/91 - * $Id: wd.c,v 1.85 1995/09/30 00:11:19 jkh Exp $ + * $Id: wd.c,v 1.86 1995/09/30 15:19:44 davidg Exp $ */ /* TODO: @@ -301,11 +301,34 @@ wdprobe(struct isa_device *dvp) /* check if we have registers that work */ outb(du->dk_port + wd_sdh, WDSD_IBM); /* set unit 0 */ outb(du->dk_port + wd_cyl_lo, 0xa5); /* wd_cyl_lo is read/write */ - if (inb(du->dk_port + wd_cyl_lo) == 0xff) /* XXX too weak */ - goto nodevice; + if (inb(du->dk_port + wd_cyl_lo) == 0xff) { /* XXX too weak */ +#ifdef ATAPI + /* There is no master, try the ATAPI slave. */ + outb(du->dk_port + wd_sdh, WDSD_IBM | 0x10); + outb(du->dk_port + wd_cyl_lo, 0xa5); + if (inb(du->dk_port + wd_cyl_lo) == 0xff) +#endif + goto nodevice; + } - if (wdreset(du) != 0 && (DELAY(RECOVERYTIME), wdreset(du)) != 0) + if (wdreset(du) == 0) + goto reset_ok; +#ifdef ATAPI + /* test for ATAPI signature */ + outb(du->dk_port + wd_sdh, WDSD_IBM); /* master */ + if (inb(du->dk_port + wd_cyl_lo) == 0x14 && + inb(du->dk_port + wd_cyl_hi) == 0xeb) + goto reset_ok; + du->dk_unit = 1; + outb(du->dk_port + wd_sdh, WDSD_IBM | 0x10); /* slave */ + if (inb(du->dk_port + wd_cyl_lo) == 0x14 && + inb(du->dk_port + wd_cyl_hi) == 0xeb) + goto reset_ok; +#endif + DELAY(RECOVERYTIME); + if (wdreset(du) != 0) goto nodevice; +reset_ok: /* execute a controller only command */ if (wdcommand(du, 0, 0, 0, 0, WDCC_DIAGNOSE) != 0 @@ -657,7 +680,7 @@ loop: bp = wdtab[ctrlr].b_actf; if (bp == NULL) { #ifdef ATAPI - if (atapi_start (ctrlr)) + if (atapi_start && atapi_start (ctrlr)) /* mark controller active in ATAPI mode */ wdtab[ctrlr].b_active = 3; #endif @@ -891,7 +914,7 @@ wdintr(int unit) #ifdef ATAPI if (wdtab[unit].b_active == 3) { /* process an ATAPI interrupt */ - if (atapi_intr (unit)) + if (atapi_intr && atapi_intr (unit)) /* ATAPI op continues */ return; /* controller is free, start new op */ @@ -1916,13 +1939,6 @@ wdreset(struct disk *du) du->dk_error = inb(wdc + wd_error); if (du->dk_error != 0x01) err = 1; /* the drive is incompatible */ - if (err) { - /* no IDE drive, test for ATAPI signature */ - int lo = inb(wdc + wd_cyl_lo); - int hi = inb(wdc + wd_cyl_hi); - if (lo == 0x14 && hi == 0xeb) - err = 0; /* ATAPI drive detected */ - } #else if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) != 0 || (du->dk_error = inb(wdc + wd_error)) != 0x01) @@ -2042,6 +2058,18 @@ wdwait(struct disk *du, u_char bits_wanted, int timeout) min_retries[du->dk_ctrlr] = timeout; #endif du->dk_status = status = inb(wdc + wd_status); +#ifdef ATAPI + /* + * Atapi drives have a very interesting feature, when attached + * as a slave on the IDE bus, and there is no master. + * They release the bus after getting the command. + * We should reselect the drive here to get the status. + */ + if (status == 0xff) { + outb(wdc + wd_sdh, WDSD_IBM | du->dk_unit << 4); + du->dk_status = status = inb(wdc + wd_status); + } +#endif if (!(status & WDCS_BUSY)) { if (status & WDCS_ERR) { du->dk_error = inb(wdc + wd_error); diff --git a/sys/pc98/pc98/atapi.h b/sys/pc98/pc98/atapi.h index cb46dcc..f22a5a2 100644 --- a/sys/pc98/pc98/atapi.h +++ b/sys/pc98/pc98/atapi.h @@ -11,7 +11,7 @@ * or modify this software as long as this message is kept with the software, * all derivative works or modified versions. * - * Version 1.8, Thu Sep 28 20:24:38 MSK 1995 + * Version 1.9, Thu Oct 12 15:53:50 MSK 1995 */ /* @@ -190,10 +190,64 @@ struct atapires { u_char error; /* error register contents */ }; +struct atapidrv { /* delayed attach info */ + int ctlr; /* IDE controller, 0/1 */ + int unit; /* drive unit, 0/1 */ + int port; /* controller base port */ + int attached; /* the drive is attached */ + struct kern_devconf *parent; /* the devconf info pattern */ +}; + +struct atapicmd { /* ATAPI command block */ + struct atapicmd *next; /* next command in queue */ + int busy; /* busy flag */ + u_char cmd[16]; /* command and args */ + int unit; /* drive unit number */ + int count; /* byte count, >0 - read, <0 - write */ + char *addr; /* data to transfer */ + void (*callback) (); /* call when done */ + void *cbarg1; /* callback arg 1 */ + void *cbarg2; /* callback arg 1 */ + struct atapires result; /* resulting error code */ +}; + +struct atapi { /* ATAPI controller data */ + u_short port; /* i/o port base */ + u_char ctrlr; /* physical controller number */ + u_char debug : 1; /* trace enable flag */ + u_char cmd16 : 1; /* 16-byte command flag */ + u_char intrcmd : 1; /* interrupt before cmd flag */ + u_char slow : 1; /* slow reaction device */ + u_char attached[2]; /* units are attached to subdrivers */ + struct atapi_params *params[2]; /* params for units 0,1 */ + struct kern_devconf *parent; /* parent configuration pattern */ + struct atapicmd *queue; /* queue of commands to perform */ + struct atapicmd *tail; /* tail of queue */ + struct atapicmd *free; /* queue of free command blocks */ + struct atapicmd cmdrq[16]; /* pool of command requests */ +}; + #ifdef KERNEL struct atapi; struct kern_devconf; -void atapi_attach (int ctlr, int unit, int port, struct kern_devconf*); + +extern struct atapidrv atapi_drvtab[4]; /* delayed attach info */ +extern int atapi_ndrv; /* the number of potential drives */ +extern struct atapi *atapi_tab; /* the table of atapi controllers */ + +#ifndef ATAPI_STATIC +# define atapi_start (*atapi_start_ptr) +# define atapi_intr (*atapi_intr_ptr) +# define atapi_debug (*atapi_debug_ptr) +# define atapi_request_wait (*atapi_request_wait_ptr) +# define atapi_request_callback (*atapi_request_callback_ptr) +# define atapi_request_immediate (*atapi_request_immediate_ptr) +#endif + +#ifndef ATAPI_MODULE +int atapi_attach (int ctlr, int unit, int port, struct kern_devconf*); +#endif + int atapi_start (int ctrlr); int atapi_intr (int ctrlr); void atapi_debug (struct atapi *ata, int on); |