at_wini: PCI-only now; one controller per instance

- remove non-PCI support, since all supported platforms with at_wini
  devices also have PCI support by now;
- correspondingly, stop using information from the BIOS altogether;
- limit each driver instance to one controller, to be in line with
  the general MINIX3 one-instance-per-controller driver model; this
  limits the number of disks per at_wini instance to four;
- go through the controllers by the order of their occurrence in the
  PCI table, thus removing the exception for compatibility devices;
- let the second at_wini instance shut down silently if there is only
  one IDE controller;
- clean up some extra code we don't need anymore, and resolve some
  WARNS=5 level warnings.

Overall, these changes should simplify automatic loading of the right
disk drivers at boot time in the future.

Change-Id: Ia64d08cfbeb9916abd68c9c2941baeb87d02a806
This commit is contained in:
David van Moolenbroek 2013-10-02 19:37:00 +02:00 committed by Lionel Sambuc
parent 89332ecdf1
commit 6d466f941b
5 changed files with 251 additions and 516 deletions

View File

@ -1,11 +1,8 @@
/* This file contains the device dependent part of a driver for the IBM-AT
* winchester controller. Written by Adri Koppes.
*
* The file contains one entry point:
*
* at_winchester_task: main entry when system is brought up
*
* Changes:
* Oct 2, 2013 drop non-PCI support; one controller per instance (David)
* Aug 19, 2005 ATA PCI support, supports SATA (Ben Gras)
* Nov 18, 2004 moved AT disk driver to user-space (Jorrit N. Herder)
* Aug 20, 2004 watchdogs replaced by sync alarms (Jorrit N. Herder)
@ -58,34 +55,24 @@ static long w_atapi_dma;
static int w_testing = 0;
static int w_silent = 0;
static int w_next_drive = 0;
static u32_t system_hz;
/* The struct wini is indexed by controller first, then drive (0-3).
* Controller 0 is always the 'compatability' ide controller, at
* the fixed locations, whether present or not.
*/
/* The struct wini is indexed by drive (0-3). */
static struct wini { /* main drive struct, one entry per drive */
unsigned state; /* drive state: deaf, initialized, dead */
unsigned short w_status; /* device status register */
unsigned base_cmd; /* command base register */
unsigned base_ctl; /* control base register */
unsigned base_dma; /* dma base register */
int dma_intseen;
unsigned irq; /* interrupt request line */
unsigned irq_need_ack; /* irq needs to be acknowledged */
unsigned char native; /* if set, drive is native (not compat.) */
unsigned char lba48; /* if set, drive supports lba48 */
unsigned char dma; /* if set, drive supports dma */
unsigned char dma_intseen; /* if set, drive has seen an interrupt */
int irq_hook_id; /* id of irq hook at the kernel */
int lba48; /* supports lba48 */
int dma; /* supports dma */
unsigned lcylinders; /* logical number of cylinders (BIOS) */
unsigned lheads; /* logical number of heads */
unsigned lsectors; /* logical number of sectors per track */
unsigned pcylinders; /* physical number of cylinders (translated) */
unsigned pheads; /* physical number of heads */
unsigned psectors; /* physical number of sectors per track */
unsigned cylinders; /* physical number of cylinders */
unsigned heads; /* physical number of heads */
unsigned sectors; /* physical number of sectors per track */
unsigned ldhpref; /* top four bytes of the LDH (head) register */
unsigned precomp; /* write precompensation cylinder / 4 */
unsigned max_count; /* max request for this drive */
unsigned open_ct; /* in-use count */
struct device part[DEV_PER_DRIVE]; /* disks and partitions */
@ -122,24 +109,9 @@ static phys_bytes prdt_phys;
#define PRDTE_FL_EOT 0x80 /* End of table */
/* IDE devices we trust are IDE devices. */
static struct quirk
{
int pci_class, pci_subclass, pci_interface;
u16_t vendor;
u16_t device;
} quirk_table[]=
{
{ 0x01, 0x04, 0x00, 0x1106, 0x3149 }, /* VIA VT6420 */
{ 0x01, 0x04, 0x00, 0x1095, 0x3512 },
{ 0x01, 0x80, -1, 0x1095, 0x3114 }, /* Silicon Image SATA */
{ 0, 0, 0, 0, 0 } /* end of list */
};
static void init_params(void);
static void init_drive(struct wini *w, int base_cmd, int base_ctl, int
base_dma, int irq, int ack, int hook, int drive);
static void init_params_pci(int);
static int w_probe(int skip, u16_t *vidp, u16_t *didp);
static void w_init(int devind, u16_t vid, u16_t did);
static int init_params(void);
static int w_do_open(devminor_t minor, int access);
static struct device *w_prepare(devminor_t dev);
static struct device *w_part(devminor_t minor);
@ -154,7 +126,6 @@ static int com_out_ext(struct command *cmd);
static int setup_dma(unsigned *sizep, endpoint_t proc_nr, iovec_t *iov,
size_t addr_offset, int do_write);
static void w_need_reset(void);
static void ack_irqs(unsigned int);
static int w_do_close(devminor_t minor);
static int w_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt,
cp_grant_id_t grant, endpoint_t user_endpt);
@ -165,34 +136,14 @@ static int w_reset(void);
static void w_intr_wait(void);
static int at_intr_wait(void);
static int w_waitfor(int mask, int value);
static int w_waitfor_dma(int mask, int value);
static int w_waitfor_dma(unsigned int mask, unsigned int value);
static void w_geometry(devminor_t minor, struct part_geom *entry);
#if ENABLE_ATAPI
static int atapi_sendpacket(u8_t *packet, unsigned cnt, int do_dma);
static int atapi_intr_wait(int dma, size_t max);
static int atapi_open(void);
static void atapi_close(void);
static int atapi_transfer(int do_write, u64_t position, endpoint_t
endpt, iovec_t *iov, unsigned int nr_req);
#endif
#define sys_voutb(out, n) at_voutb((out), (n))
static int at_voutb(pvb_pair_t *, int n);
#define sys_vinb(in, n) at_vinb((in), (n))
static int at_vinb(pvb_pair_t *, int n);
#undef sys_outb
#undef sys_inb
#undef sys_outl
static int at_out(int line, u32_t port, u32_t value, char *typename,
int type);
static int at_in(int line, u32_t port, u32_t *value, char *typename,
int type);
#define sys_outb(p, v) at_out(__LINE__, (p), (v), "outb", _DIO_BYTE)
#define sys_inb(p, v) at_in(__LINE__, (p), (v), "inb", _DIO_BYTE)
#define sys_outl(p, v) at_out(__LINE__, (p), (v), "outl", _DIO_LONG)
/* Entry points to this driver. */
static struct blockdriver w_dtab = {
@ -209,9 +160,6 @@ static struct blockdriver w_dtab = {
/* SEF functions and variables. */
static void sef_local_startup(void);
static int sef_cb_init_fresh(int type, sef_init_info_t *info);
EXTERN int sef_cb_lu_prepare(int state);
EXTERN int sef_cb_lu_state_isvalid(int state);
EXTERN void sef_cb_lu_state_dump(int state);
/*===========================================================================*
* at_winchester_task *
@ -252,6 +200,9 @@ static void sef_local_startup(void)
static int sef_cb_init_fresh(int type, sef_init_info_t *UNUSED(info))
{
/* Initialize the at_wini driver. */
int skip, devind;
u16_t vid, did;
system_hz = sys_hz();
if (!(tmp_buf = alloc_contig(2*DMA_BUF_SIZE, AC_ALIGN4K, NULL)))
@ -261,7 +212,23 @@ static int sef_cb_init_fresh(int type, sef_init_info_t *UNUSED(info))
wakeup_ticks = WAKEUP_TICKS;
/* Set special disk parameters. */
init_params();
skip = init_params();
/* Find the PCI device to use. If none found, terminate immediately. */
devind = w_probe(skip, &vid, &did);
if (devind < 0) {
/* For now, complain only if even the first at_wini instance cannot
* find a device. There may be only one IDE controller after all,
* but if there are none, the system should probably be booted with
* another driver, and that's something the user might want to know.
*/
if (w_instance == 0)
panic("no matching device found");
return ENODEV; /* the actual error code doesn't matter */
}
/* Initialize the device. */
w_init(devind, vid, did);
/* Announce we are up! */
blockdriver_announce(type);
@ -272,16 +239,10 @@ static int sef_cb_init_fresh(int type, sef_init_info_t *UNUSED(info))
/*===========================================================================*
* init_params *
*===========================================================================*/
static void init_params(void)
static int init_params(void)
{
/* This routine is called at startup to initialize the drive parameters. */
u16_t parv[2];
unsigned int vector, size;
int drive, nr_drives;
struct wini *wn;
u8_t params[16];
int s;
int drive;
long wakeup_secs = WAKEUP_SECS;
/* Boot variables. */
@ -316,75 +277,32 @@ static void init_params(void)
}
}
if (w_instance == 0) {
/* Get the number of drives from the BIOS data area */
s=sys_readbios(NR_HD_DRIVES_ADDR, params, NR_HD_DRIVES_SIZE);
if (s != OK)
panic("Couldn't read BIOS: %d", s);
if ((nr_drives = params[0]) > 2) nr_drives = 2;
for (drive = 0, wn = wini; drive < COMPAT_DRIVES; drive++, wn++) {
if (drive < nr_drives) {
/* Copy the BIOS parameter vector */
vector = (drive == 0) ? BIOS_HD0_PARAMS_ADDR :
BIOS_HD1_PARAMS_ADDR;
size = (drive == 0) ? BIOS_HD0_PARAMS_SIZE :
BIOS_HD1_PARAMS_SIZE;
s=sys_readbios(vector, parv, size);
if (s != OK)
panic("Couldn't read BIOS: %d", s);
/* Calculate the address of the parameters and copy them */
s=sys_readbios(hclick_to_physb(parv[1]) + parv[0],
params, 16L);
if (s != OK)
panic("Couldn't copy parameters: %d", s);
/* Copy the parameters to the structures of the drive */
wn->lcylinders = bp_cylinders(params);
wn->lheads = bp_heads(params);
wn->lsectors = bp_sectors(params);
wn->precomp = bp_precomp(params) >> 2;
}
/* Fill in non-BIOS parameters. */
init_drive(wn,
drive < 2 ? REG_CMD_BASE0 : REG_CMD_BASE1,
drive < 2 ? REG_CTL_BASE0 : REG_CTL_BASE1,
0 /* no DMA */, NO_IRQ, 0, 0, drive);
w_next_drive++;
}
}
/* Look for controllers on the pci bus. Skip none the first instance,
* skip one and then 2 for every instance, for every next instance.
*/
if (w_instance == 0)
init_params_pci(0);
else
init_params_pci(w_instance*2-1);
for (drive = 0; drive < MAX_DRIVES; drive++)
wini[drive].state = IGNORING;
return (int) w_instance;
}
#define ATA_IF_NOTCOMPAT1 (1L << 0)
#define ATA_IF_NOTCOMPAT2 (1L << 2)
/*===========================================================================*
* init_drive *
*===========================================================================*/
static void init_drive(struct wini *w, int base_cmd, int base_ctl,
int base_dma, int irq, int ack, int hook, int drive)
static void init_drive(int drive, int base_cmd, int base_ctl, int base_dma,
int native, int hook)
{
struct wini *w;
w = &wini[drive];
w->state = 0;
w->w_status = 0;
w->base_cmd = base_cmd;
w->base_ctl = base_ctl;
w->base_dma = base_dma;
if(w_pci_debug)
printf("at_wini%ld: drive %d: base_cmd 0x%x, base_ctl 0x%x, base_dma 0x%x\n",
w_instance, w-wini, w->base_cmd, w->base_ctl, w->base_dma);
w->irq = irq;
w->irq_need_ack = ack;
if (w_pci_debug)
printf("at_wini%ld: drive %d: base_cmd 0x%x, base_ctl 0x%x, "
"base_dma 0x%x\n", w_instance, drive, w->base_cmd, w->base_ctl,
w->base_dma);
w->native = native;
w->irq_hook_id = hook;
w->ldhpref = ldh_init(drive);
w->max_count = MAX_SECS << SECTOR_SHIFT;
@ -392,188 +310,144 @@ static void init_drive(struct wini *w, int base_cmd, int base_ctl,
w->dma = 0;
}
static int quirkmatch(struct quirk *table, u8_t bcr, u8_t scr, u8_t interface, u16_t vid, u16_t did) {
while(table->vendor) {
if(table->vendor == vid && table->device == did &&
table->pci_class == bcr &&
table->pci_subclass == scr &&
(table->pci_interface == -1 ||
table->pci_interface == interface)) {
return 1;
}
table++;
}
return 0;
}
static void
pci_busmaster(int devind)
/*===========================================================================*
* w_probe *
*===========================================================================*/
static int w_probe(int skip, u16_t *vidp, u16_t *didp)
{
u16_t cr;
/* Go through the PCI devices that have been made visible to us, skipping as
* many as requested and then reserving the first one after that. We assume
* that all visible devices are in fact devices we can handle.
*/
int r, devind;
/* Enable busmastering if necessary. */
cr = pci_attr_r16(devind, PCI_CR);
if (!(cr & PCI_CR_MAST_EN)) {
pci_attr_w16(devind, PCI_CR, cr | PCI_CR_MAST_EN);
pci_init();
r = pci_first_dev(&devind, vidp, didp);
if (r <= 0)
return -1;
while (skip--) {
r = pci_next_dev(&devind, vidp, didp);
if (r <= 0)
return -1;
}
pci_reserve(devind);
return devind;
}
/*===========================================================================*
* init_params_pci *
* w_init *
*===========================================================================*/
static void init_params_pci(int skip)
static void w_init(int devind, u16_t vid, u16_t did)
{
int i, r, devind, drive, pci_compat = 0;
int irq, irq_hook;
u8_t bcr, scr, interface;
u16_t vid, did;
u32_t base_dma, t3;
pci_init();
for(drive = w_next_drive; drive < MAX_DRIVES; drive++)
wini[drive].state = IGNORING;
for(r = pci_first_dev(&devind, &vid, &did); r != 0;
r = pci_next_dev(&devind, &vid, &did)) {
int quirk = 0;
/* Except class 01h (mass storage), subclass be 01h (ATA).
* Also check listed RAID controllers.
/* Initialize drives on the controller that we found and reserved. Each
* controller has two channels, each of which may have up to two disks
* attached, so the maximum number of disks per controller is always four.
* In this function, we always initialize the slots for all four disks; later,
* during normal operation, we determine whether the disks are actually there.
* For pure IDE devices (as opposed to e.g. RAID devices), each of the two
* channels on the controller may be in native or compatibility mode. The PCI
* interface field tells us which channel is in which mode. For native
* channels, we get the IRQ and the channel's base control and command
* addresses from the PCI slot, and we manually acknowledge interrupts. For
* compatibility channels, we use the hardcoded legacy IRQs and addresses, and
* enable automatic IRQ reenabling. In both cases, we get the base DMA address
* from the PCI slot if it is there.
*/
int r, irq, native_hook, compat_hook, is_ide, nhooks;
u8_t bcr, scr, interface;
u16_t cr;
u32_t base_cmd, base_ctl, base_dma;
bcr= pci_attr_r8(devind, PCI_BCR);
scr= pci_attr_r8(devind, PCI_SCR);
interface= pci_attr_r8(devind, PCI_PIFR);
t3= ((bcr << 16) | (scr << 8) | interface);
if (bcr == PCI_BCR_MASS_STORAGE && scr == PCI_MS_IDE)
; /* Okay */
else if(quirkmatch(quirk_table, bcr, scr, interface, vid, did)) {
quirk = 1;
} else
continue; /* Unsupported device class */
/* Found a controller.
* Programming interface register tells us more.
*/
is_ide = (bcr == PCI_BCR_MASS_STORAGE && scr == PCI_MS_IDE);
irq = pci_attr_r8(devind, PCI_ILR);
/* Any non-compat drives? */
if (quirk || (interface & (ATA_IF_NOTCOMPAT1 | ATA_IF_NOTCOMPAT2))) {
if (w_next_drive >= MAX_DRIVES)
{
/* We can't accept more drives, but have to search for
* controllers operating in compatibility mode.
*/
continue;
}
irq_hook = irq;
if (skip > 0) {
if (w_pci_debug)
{
printf(
"atapci skipping controller (remain %d)\n",
skip);
}
skip--;
continue;
}
if(pci_reserve_ok(devind) != OK) {
printf("at_wini%ld: pci_reserve %d failed - "
"ignoring controller!\n",
w_instance, devind);
continue;
}
pci_busmaster(devind);
if (sys_irqsetpolicy(irq, 0, &irq_hook) != OK) {
printf("atapci: couldn't set IRQ policy %d\n", irq);
continue;
}
if (sys_irqenable(&irq_hook) != OK) {
printf("atapci: couldn't enable IRQ line %d\n", irq);
continue;
}
}
base_dma = pci_attr_r32(devind, PCI_BAR_5) & PCI_BAR_IO_MASK;
/* Primary channel not in compatability mode? */
if (quirk || (interface & ATA_IF_NOTCOMPAT1)) {
u32_t base_cmd, base_ctl;
nhooks = 0; /* we don't care about notify IDs, but they must be unique */
/* Any native drives? Then register their native IRQ first. */
if (!is_ide || (interface & (ATA_IF_NATIVE0 | ATA_IF_NATIVE1))) {
native_hook = nhooks++;
if ((r = sys_irqsetpolicy(irq, 0, &native_hook)) != OK)
panic("couldn't set native IRQ policy %d: %d", irq, r);
if ((r = sys_irqenable(&native_hook)) != OK)
panic("couldn't enable native IRQ line %d: %d", irq, r);
}
/* Add drives on the primary channel. */
if (!is_ide || (interface & ATA_IF_NATIVE0)) {
base_cmd = pci_attr_r32(devind, PCI_BAR) & PCI_BAR_IO_MASK;
base_ctl = pci_attr_r32(devind, PCI_BAR_2) & PCI_BAR_IO_MASK;
if (base_cmd != REG_CMD_BASE0 && base_cmd != REG_CMD_BASE1) {
init_drive(&wini[w_next_drive],
base_cmd, base_ctl+PCI_CTL_OFF,
base_dma, irq, 1, irq_hook, 0);
init_drive(&wini[w_next_drive+1],
base_cmd, base_ctl+PCI_CTL_OFF,
base_dma, irq, 1, irq_hook, 1);
init_drive(0, base_cmd, base_ctl+PCI_CTL_OFF, base_dma, TRUE,
native_hook);
init_drive(1, base_cmd, base_ctl+PCI_CTL_OFF, base_dma, TRUE,
native_hook);
if (w_pci_debug)
printf("at_wini%ld: atapci %d: 0x%x 0x%x irq %d\n",
printf("at_wini%ld: native 0 on %d: 0x%x 0x%x irq %d\n",
w_instance, devind, base_cmd, base_ctl, irq);
w_next_drive += 2;
} else printf("at_wini%ld: atapci: ignored drives on primary channel, base %x\n", w_instance, base_cmd);
}
else
{
/* Update base_dma for compatibility device */
for (i= 0; i<MAX_DRIVES; i++)
{
if (wini[i].base_cmd == REG_CMD_BASE0) {
wini[i].base_dma= base_dma;
if(w_pci_debug)
printf("at_wini%ld: drive %d: base_dma 0x%x\n",
w_instance, i, wini[i].base_dma);
pci_compat = 1;
}
}
} else {
/* Register first compatibility IRQ. */
compat_hook = nhooks++;
if ((r = sys_irqsetpolicy(AT_WINI_0_IRQ, IRQ_REENABLE,
&compat_hook)) != OK)
panic("couldn't set compat(0) IRQ policy: %d", r);
if ((r = sys_irqenable(&compat_hook)) != OK)
panic("couldn't enable compat(0) IRQ line: %d", r);
init_drive(0, REG_CMD_BASE0, REG_CTL_BASE0, base_dma, FALSE,
compat_hook);
init_drive(1, REG_CMD_BASE0, REG_CTL_BASE0, base_dma, FALSE,
compat_hook);
if (w_pci_debug)
printf("at_wini%ld: compat 0 on %d\n", w_instance, devind);
}
/* Secondary channel not in compatability mode? */
if (quirk || (interface & ATA_IF_NOTCOMPAT2)) {
u32_t base_cmd, base_ctl;
base_cmd = pci_attr_r32(devind, PCI_BAR_3) & PCI_BAR_IO_MASK;
base_ctl = pci_attr_r32(devind, PCI_BAR_4) & PCI_BAR_IO_MASK;
/* Add drives on the secondary channel. */
if (base_dma != 0)
base_dma += PCI_DMA_2ND_OFF;
if (base_cmd != REG_CMD_BASE0 && base_cmd != REG_CMD_BASE1) {
init_drive(&wini[w_next_drive],
base_cmd, base_ctl+PCI_CTL_OFF, base_dma,
irq, 1, irq_hook, 2);
init_drive(&wini[w_next_drive+1],
base_cmd, base_ctl+PCI_CTL_OFF, base_dma,
irq, 1, irq_hook, 3);
if (!is_ide || (interface & ATA_IF_NATIVE1)) {
base_cmd = pci_attr_r32(devind, PCI_BAR_3) & PCI_BAR_IO_MASK;
base_ctl = pci_attr_r32(devind, PCI_BAR_4) & PCI_BAR_IO_MASK;
init_drive(2, base_cmd, base_ctl+PCI_CTL_OFF, base_dma, TRUE,
native_hook);
init_drive(3, base_cmd, base_ctl+PCI_CTL_OFF, base_dma, TRUE,
native_hook);
if (w_pci_debug)
printf("at_wini%ld: atapci %d: 0x%x 0x%x irq %d\n",
printf("at_wini%ld: native 1 on %d: 0x%x 0x%x irq %d\n",
w_instance, devind, base_cmd, base_ctl, irq);
w_next_drive += 2;
} else printf("at_wini%ld: atapci: ignored drives on "
"secondary channel, base %x\n", w_instance, base_cmd);
}
else
{
/* Update base_dma for compatibility device */
for (i= 0; i<MAX_DRIVES; i++)
{
if (wini[i].base_cmd == REG_CMD_BASE1 && base_dma != 0) {
wini[i].base_dma= base_dma+PCI_DMA_2ND_OFF;
} else {
/* Register secondary compatibility IRQ. */
compat_hook = nhooks++;
if ((r = sys_irqsetpolicy(AT_WINI_1_IRQ, IRQ_REENABLE,
&compat_hook)) != OK)
panic("couldn't set compat(1) IRQ policy: %d", r);
if ((r = sys_irqenable(&compat_hook)) != OK)
panic("couldn't enable compat(1) IRQ line: %d", r);
init_drive(2, REG_CMD_BASE1, REG_CTL_BASE1, base_dma, FALSE,
compat_hook);
init_drive(3, REG_CMD_BASE1, REG_CTL_BASE1, base_dma, FALSE,
compat_hook);
if (w_pci_debug)
printf("at_wini%ld: drive %d: base_dma 0x%x\n",
w_instance, i, wini[i].base_dma);
pci_compat = 1;
}
}
printf("at_wini%ld: compat 1 on %d\n", w_instance, devind);
}
if(pci_compat) {
if(pci_reserve_ok(devind) != OK) {
printf("at_wini%ld (compat): pci_reserve %d failed!\n",
w_instance, devind);
} else pci_busmaster(devind);
}
}
/* Enable busmastering if necessary. */
cr = pci_attr_r16(devind, PCI_CR);
if (!(cr & PCI_CR_MAST_EN))
pci_attr_w16(devind, PCI_CR, cr | PCI_CR_MAST_EN);
}
/*===========================================================================*
@ -599,7 +473,7 @@ static int w_do_open(devminor_t minor, int access)
/* Try to identify the device. */
if (w_identify() != OK) {
#if VERBOSE
printf("%s: probe failed\n", w_name());
printf("%s: identification failed\n", w_name());
#endif
if (wn->state & DEAF){
int err = w_reset();
@ -621,21 +495,17 @@ static int w_do_open(devminor_t minor, int access)
}
}
#if ENABLE_ATAPI
if ((wn->state & ATAPI) && (access & BDEV_W_BIT))
return(EACCES);
#endif
/* Partition the drive if it's being opened for the first time,
* or being opened after being closed.
*/
if (wn->open_ct == 0) {
#if ENABLE_ATAPI
if (wn->state & ATAPI) {
int r;
if ((r = atapi_open()) != OK) return(r);
}
#endif
/* Partition the disk. */
partition(&w_dtab, w_drive * DEV_PER_DRIVE, P_PRIMARY,
@ -655,11 +525,13 @@ static struct device *w_prepare(devminor_t device)
if (device >= 0 && device < NR_MINORS) { /* d0, d0p[0-3], d1, ... */
w_drive = device / DEV_PER_DRIVE; /* save drive number */
if (w_drive >= MAX_DRIVES) return(NULL);
w_wn = &wini[w_drive];
w_dv = &w_wn->part[device % DEV_PER_DRIVE];
} else
if ((unsigned) (device -= MINOR_d0p0s0) < NR_SUBDEVS) {/*d[0-7]p[0-3]s[0-3]*/
w_drive = device / SUB_PER_DRIVE;
if (w_drive >= MAX_DRIVES) return(NULL);
w_wn = &wini[w_drive];
w_dv = &w_wn->subpart[device % SUB_PER_DRIVE];
} else {
@ -806,24 +678,14 @@ static int w_identify(void)
if ((s=sys_insw(wn->base_cmd + REG_DATA, SELF, tmp_buf, SECTOR_SIZE)) != OK)
panic("Call to sys_insw() failed: %d", s);
#if 0
if (id_word(0) & ID_GEN_NOT_ATA)
{
printf("%s: not an ATA device?\n", w_name());
wakeup_ticks = prev_wakeup;
w_testing = 0;
return ERR;
}
#endif
/* This is an ATA device. */
wn->state |= SMART;
/* Preferred CHS translation mode. */
wn->pcylinders = id_word(1);
wn->pheads = id_word(3);
wn->psectors = id_word(6);
size = (u32_t) wn->pcylinders * wn->pheads * wn->psectors;
wn->cylinders = id_word(1);
wn->heads = id_word(3);
wn->sectors = id_word(6);
size = (u32_t) wn->cylinders * wn->heads * wn->sectors;
w= id_word(ID_CAPABILITIES);
if ((w & ID_CAP_LBA) && size > 512L*1024*2) {
@ -856,20 +718,7 @@ static int w_identify(void)
check_dma(wn);
}
if (wn->lcylinders == 0 || wn->lheads == 0 || wn->lsectors == 0) {
/* No BIOS parameters? Then make some up. */
wn->lcylinders = wn->pcylinders;
wn->lheads = wn->pheads;
wn->lsectors = wn->psectors;
while (wn->lcylinders > 1024) {
wn->lheads *= 2;
wn->lcylinders /= 2;
}
}
#if ENABLE_ATAPI
} else
if (cmd.command = ATAPI_IDENTIFY,
} else if (cmd.command = ATAPI_IDENTIFY,
com_simple(&cmd) == OK && w_waitfor(STATUS_DRQ, STATUS_DRQ) &&
!(wn->w_status & (STATUS_ERR|STATUS_WF))) {
/* An ATAPI device. */
@ -881,20 +730,13 @@ static int w_identify(void)
size = 0; /* Size set later. */
check_dma(wn);
#endif
} else {
/* Not an ATA device; no translations, no special features. Don't
* touch it unless the BIOS knows about it.
* touch it.
*/
if (wn->lcylinders == 0) {
wakeup_ticks = prev_wakeup;
w_testing = 0;
return(ERR);
} /* no BIOS parameters */
wn->pcylinders = wn->lcylinders;
wn->pheads = wn->lheads;
wn->psectors = wn->lsectors;
size = (u32_t) wn->pcylinders * wn->pheads * wn->psectors;
}
/* Restore wakeup_ticks and unset testing mode. */
@ -909,15 +751,6 @@ static int w_identify(void)
return(ERR);
}
if (wn->irq == NO_IRQ) {
/* Everything looks OK; register IRQ so we can stop polling. */
wn->irq = w_drive < 2 ? AT_WINI_0_IRQ : AT_WINI_1_IRQ;
wn->irq_hook_id = wn->irq; /* id to be returned if interrupt occurs */
if ((s=sys_irqsetpolicy(wn->irq, IRQ_REENABLE, &wn->irq_hook_id)) != OK)
panic("couldn't set IRQ policy: %d", s);
if ((s=sys_irqenable(&wn->irq_hook_id)) != OK)
panic("couldn't enable IRQ line: %d", s);
}
wn->state |= IDENTIFIED;
return(OK);
}
@ -946,11 +779,7 @@ static int w_io_test(void)
static char *buf;
ssize_t r;
#ifdef CD_SECTOR_SIZE
#define BUFSIZE CD_SECTOR_SIZE
#else
#define BUFSIZE SECTOR_SIZE
#endif
STATICINIT(buf, BUFSIZE);
iov.iov_addr = (vir_bytes) buf;
@ -971,7 +800,7 @@ static int w_io_test(void)
w_testing = 1;
/* Try I/O on the actual drive (not any (sub)partition). */
r = w_transfer(w_drive * DEV_PER_DRIVE, FALSE /*do_write*/, ((u64_t)(0)),
r = w_transfer(w_drive * DEV_PER_DRIVE, FALSE /*do_write*/, 0,
SELF, &iov, 1, BDEV_NOFLAGS);
/* Switch back. */
@ -1009,9 +838,9 @@ static int w_specify(void)
if (!(wn->state & ATAPI)) {
/* Specify parameters: precompensation, number of heads and sectors. */
cmd.precomp = wn->precomp;
cmd.count = wn->psectors;
cmd.ldh = w_wn->ldhpref | (wn->pheads - 1);
cmd.precomp = 0;
cmd.count = wn->sectors;
cmd.ldh = w_wn->ldhpref | (wn->heads - 1);
cmd.command = CMD_SPECIFY; /* Specify some parameters */
/* Output command block and see if controller accepts the parameters. */
@ -1035,13 +864,12 @@ static int w_specify(void)
/*===========================================================================*
* do_transfer *
*===========================================================================*/
static int do_transfer(const struct wini *wn, unsigned int precomp,
unsigned int count, unsigned int sector,
unsigned int do_write, int do_dma)
static int do_transfer(const struct wini *wn, unsigned int count,
unsigned int sector, unsigned int do_write, int do_dma)
{
struct command cmd;
unsigned int sector_high;
unsigned secspcyl = wn->pheads * wn->psectors;
unsigned secspcyl = wn->heads * wn->sectors;
int do_lba48;
sector_high= 0; /* For future extensions */
@ -1058,7 +886,7 @@ static int do_transfer(const struct wini *wn, unsigned int precomp,
}
}
cmd.precomp = precomp;
cmd.precomp = 0;
cmd.count = count;
if (do_dma)
{
@ -1096,8 +924,8 @@ static int do_transfer(const struct wini *wn, unsigned int precomp,
} else {
int cylinder, head, sec;
cylinder = sector / secspcyl;
head = (sector % secspcyl) / wn->psectors;
sec = sector % wn->psectors;
head = (sector % secspcyl) / wn->sectors;
sec = sector % wn->sectors;
cmd.sector = sec + 1;
cmd.cyl_lo = cylinder & BYTE;
cmd.cyl_hi = (cylinder >> 8) & BYTE;
@ -1179,11 +1007,11 @@ static ssize_t w_transfer(
{
struct wini *wn;
iovec_t *iop, *iov_end = iov + nr_req;
int n, r, s, errors, do_dma;
int r, s, errors, do_dma;
unsigned long block;
u32_t w_status;
u64_t dv_size;
unsigned nbytes;
unsigned int n, nbytes;
unsigned dma_buf_offset;
ssize_t total = 0;
size_t addr_offset = 0;
@ -1193,11 +1021,9 @@ static ssize_t w_transfer(
wn = w_wn;
dv_size = w_dv->dv_size;
#if ENABLE_ATAPI
if (w_wn->state & ATAPI) {
return atapi_transfer(do_write, position, proc_nr, iov, nr_req);
}
#endif
/* Check disk address. */
if ((unsigned)(position % SECTOR_SIZE) != 0) return(EINVAL);
@ -1237,8 +1063,7 @@ static ssize_t w_transfer(
}
/* Tell the controller to transfer nbytes bytes. */
r = do_transfer(wn, wn->precomp, (nbytes >> SECTOR_SHIFT),
block, do_write, do_dma);
r = do_transfer(wn, (nbytes >> SECTOR_SHIFT), block, do_write, do_dma);
if (do_dma)
start_dma(wn, do_write);
@ -1427,7 +1252,7 @@ struct command *cmd; /* Command block */
wn->w_status = STATUS_ADMBSY;
w_command = cmd->command;
pv_set(outbyte[0], base_ctl + REG_CTL, wn->pheads >= 8 ? CTL_EIGHTHEADS : 0);
pv_set(outbyte[0], base_ctl + REG_CTL, wn->heads >= 8 ? CTL_EIGHTHEADS : 0);
pv_set(outbyte[1], base_cmd + REG_PRECOMP, cmd->precomp);
pv_set(outbyte[2], base_cmd + REG_COUNT, cmd->count);
pv_set(outbyte[3], base_cmd + REG_SECTOR, cmd->sector);
@ -1642,9 +1467,7 @@ static int w_do_close(devminor_t minor)
if (w_prepare(minor) == NULL)
return(ENXIO);
w_wn->open_ct--;
#if ENABLE_ATAPI
if (w_wn->open_ct == 0 && (w_wn->state & ATAPI)) atapi_close();
#endif
return(OK);
}
@ -1733,7 +1556,7 @@ static int w_reset(void)
for (wn = wini; wn < &wini[MAX_DRIVES]; wn++) {
if (wn->base_cmd == w_wn->base_cmd) {
wn->state &= ~DEAF;
if (w_wn->irq_need_ack) {
if (w_wn->native) {
/* Make sure irq is actually enabled.. */
sys_irqenable(&w_wn->irq_hook_id);
}
@ -1755,14 +1578,13 @@ static void w_intr_wait(void)
message m;
int ipc_status;
if (w_wn->irq != NO_IRQ) {
if (w_wn->state & IDENTIFIED) {
/* Wait for an interrupt that sets w_status to "not busy".
* (w_timeout() also clears w_status.)
*/
while (w_wn->w_status & (STATUS_ADMBSY|STATUS_BSY)) {
int rr;
if((rr=driver_receive(ANY, &m, &ipc_status)) != OK)
panic("driver_receive failed: %d", rr);
if ((r=driver_receive(ANY, &m, &ipc_status)) != OK)
panic("driver_receive failed: %d", r);
if (is_ipc_notify(ipc_status)) {
switch (_ENDPOINT_P(m.m_source)) {
case CLOCK:
@ -1776,7 +1598,7 @@ static void w_intr_wait(void)
if (r != 0)
panic("sys_inb failed: %d", r);
w_wn->w_status= w_status;
ack_irqs(m.NOTIFY_ARG);
w_hw_int(m.NOTIFY_ARG);
break;
default:
/*
@ -1795,7 +1617,7 @@ static void w_intr_wait(void)
}
}
} else {
/* Interrupt not yet allocated; use polling. */
/* Device not yet identified; use polling. */
(void) w_waitfor(STATUS_BSY, 0);
}
}
@ -1855,8 +1677,8 @@ int value; /* required status */
* w_waitfor_dma *
*===========================================================================*/
static int w_waitfor_dma(mask, value)
int mask; /* status mask */
int value; /* required status */
unsigned int mask; /* status mask */
unsigned value; /* required status */
{
/* Wait until controller is in the required state. Return zero on timeout.
*/
@ -1891,13 +1713,16 @@ static void w_geometry(devminor_t minor, struct part_geom *entry)
entry->heads = 64;
entry->sectors = 32;
} else { /* Return logical geometry. */
entry->cylinders = wn->lcylinders;
entry->heads = wn->lheads;
entry->sectors = wn->lsectors;
entry->cylinders = wn->cylinders;
entry->heads = wn->heads;
entry->sectors = wn->sectors;
while (entry->cylinders > 1024) {
entry->heads *= 2;
entry->cylinders /= 2;
}
}
}
#if ENABLE_ATAPI
/*===========================================================================*
* atapi_open *
*===========================================================================*/
@ -2052,7 +1877,7 @@ static int atapi_transfer(
} else {
dmabytes += nbytes;
while (nbytes > 0) {
vir_bytes chunk = nbytes;
chunk = nbytes;
if (chunk > iov->iov_size)
chunk = iov->iov_size;
@ -2205,9 +2030,6 @@ int do_dma;
return(OK);
}
#endif /* ENABLE_ATAPI */
/*===========================================================================*
* w_ioctl *
*===========================================================================*/
@ -2292,24 +2114,14 @@ static int w_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt,
/*===========================================================================*
* w_hw_int *
*===========================================================================*/
static void w_hw_int(unsigned int irqs)
{
/* Leftover interrupt(s) received; ack it/them. */
ack_irqs(irqs);
}
/*===========================================================================*
* ack_irqs *
*===========================================================================*/
static void ack_irqs(unsigned int irqs)
static void w_hw_int(unsigned int UNUSED(irqs))
{
/* Leftover interrupt(s) received; ack it/them. For native drives only. */
unsigned int drive;
u32_t w_status;
for (drive = 0; drive < MAX_DRIVES; drive++) {
if (!(wini[drive].state & IGNORING) && wini[drive].irq_need_ack &&
((1L << wini[drive].irq) & irqs)) {
if (!(wini[drive].state & IGNORING) && wini[drive].native) {
if (sys_inb((wini[drive].base_cmd + REG_STATUS),
&w_status) != OK)
{
@ -2360,8 +2172,6 @@ static char *strerr(int e)
return str;
}
#if ENABLE_ATAPI
/*===========================================================================*
* atapi_intr_wait *
*===========================================================================*/
@ -2432,55 +2242,3 @@ static int atapi_intr_wait(int UNUSED(do_dma), size_t UNUSED(max))
wn->w_status |= STATUS_ADMBSY; /* Assume not done yet. */
return(r);
}
#endif /* ENABLE_ATAPI */
#undef sys_voutb
#undef sys_vinb
static int at_voutb(pvb_pair_t *pvb, int n)
{
int s, i;
if ((s=sys_voutb(pvb,n)) == OK)
return OK;
printf("at_wini%ld: sys_voutb failed: %d pvb (%d):\n", w_instance, s, n);
for(i = 0; i < n; i++)
printf("%2d: %4x -> %4x\n", i, pvb[i].value, pvb[i].port);
panic("sys_voutb failed");
}
static int at_vinb(pvb_pair_t *pvb, int n)
{
int s, i;
if ((s=sys_vinb(pvb,n)) == OK)
return OK;
printf("at_wini%ld: sys_vinb failed: %d pvb (%d):\n", w_instance, s, n);
for(i = 0; i < n; i++)
printf("%2d: %4x\n", i, pvb[i].port);
panic("sys_vinb failed");
}
static int at_out(int line, u32_t port, u32_t value, char *typename, int type)
{
int s;
s = sys_out(port, value, type);
if(s == OK)
return OK;
printf("at_wini%ld: line %d: %s failed: %d; %x -> %x\n",
w_instance, line, typename, s, value, port);
panic("sys_out failed");
}
static int at_in(int line, u32_t port, u32_t *value, char *typename, int type)
{
int s;
s = sys_in(port, value, type);
if(s == OK)
return OK;
printf("at_wini%ld: line %d: %s failed: %d; port %x\n",
w_instance, line, typename, s, port);
panic("sys_in failed");
}

View File

@ -4,7 +4,6 @@
#define VERBOSE 0 /* display identify messages during boot */
#define VERBOSE_DMA 0 /* display DMA debugging information */
#define ENABLE_ATAPI 1 /* add ATAPI cd-rom support to driver */
#define ATAPI_DEBUG 0 /* To debug ATAPI code. */
@ -129,7 +128,6 @@
* regular LBA.
*/
#if ENABLE_ATAPI
#define ERROR_SENSE 0xF0 /* sense key mask */
#define SENSE_NONE 0x00 /* no sense key */
#define SENSE_RECERR 0x10 /* recovered error */
@ -156,7 +154,6 @@
#define REG_CNT_LO 4 /* low byte of cylinder number */
#define REG_CNT_HI 5 /* high byte of cylinder number */
#define REG_DRIVE 6 /* drive select */
#endif
#define REG_STATUS 7 /* status */
#define STATUS_BSY 0x80 /* controller busy */
@ -167,15 +164,10 @@
#define STATUS_CORR 0x04 /* correctable error occurred */
#define STATUS_CHECK 0x01 /* check error */
#if ENABLE_ATAPI
#define ATAPI_PACKETCMD 0xA0 /* packet command */
#define ATAPI_IDENTIFY 0xA1 /* identify drive */
#define SCSI_READ10 0x28 /* read from disk */
#define SCSI_SENSE 0x03 /* sense request */
#endif /* ATAPI */
/* Interrupt request lines. */
#define NO_IRQ 0 /* no IRQ set yet */
#define ATAPI_PACKETSIZE 12
#define SENSE_PACKETSIZE 18
@ -189,12 +181,12 @@
#define WAKEUP_TICKS (WAKEUP_SECS*system_hz)
/* Miscellaneous. */
#define MAX_DRIVES 8
#define COMPAT_DRIVES 4
#define MAX_DRIVES 4 /* max number of actual drives per instance */
#define MAX_DRIVENODES 8 /* number of drive nodes, for node numbering */
#define MAX_SECS 256 /* controller can transfer this many sectors */
#define MAX_ERRORS 4 /* how often to try rd/wt before quitting */
#define NR_MINORS (MAX_DRIVES * DEV_PER_DRIVE)
#define NR_SUBDEVS (MAX_DRIVES * SUB_PER_DRIVE)
#define NR_MINORS (MAX_DRIVENODES * DEV_PER_DRIVE)
#define NR_SUBDEVS (MAX_DRIVENODES * SUB_PER_DRIVE)
#define DELAY_USECS 1000 /* controller timeout in microseconds */
#define DELAY_TICKS 1 /* controller timeout in ticks */
#define DEF_TIMEOUT_USECS 5000000L /* controller timeout in microseconds */
@ -203,18 +195,15 @@
#define INITIALIZED 0x01 /* drive is initialized */
#define DEAF 0x02 /* controller must be reset */
#define SMART 0x04 /* drive supports ATA commands */
#if ENABLE_ATAPI
#define ATAPI 0x08 /* it is an ATAPI device */
#else
#define ATAPI 0 /* don't bother with ATAPI; optimise out */
#endif
#define IDENTIFIED 0x10 /* w_identify done successfully */
#define IGNORING 0x20 /* w_identify failed once */
#define NO_DMA_VAR "ata_no_dma"
/* BIOS parameter table layout. */
#define bp_cylinders(t) (t[0] | (t[1] << 8))
#define bp_heads(t) (t[2])
#define bp_precomp(t) (t[5] | (t[6] << 8))
#define bp_sectors(t) (t[14])
#define ATA_IF_NATIVE0 (1L << 0) /* first channel is in native mode */
#define ATA_IF_NATIVE1 (1L << 2) /* second channel is in native mode */
extern int sef_cb_lu_prepare(int state);
extern int sef_cb_lu_state_isvalid(int state);
extern void sef_cb_lu_state_dump(int state);

View File

@ -40,7 +40,7 @@ then if [ -e $ACPI -a -n "`sysenv acpi`" ]
/bin/service -c up /sbin/virtio_blk -dev /dev/c0d0 -label virtio_blk_0 -args instance=0
else
/bin/service -c up /sbin/at_wini -dev /dev/c0d0 -label at_wini_0
/bin/service -cr up /sbin/at_wini -dev /dev/c1d0 -label at_wini_1 -args instance=1
/bin/service -cr up /sbin/at_wini -dev /dev/c1d0 -label at_wini_1 -args instance=1 2>/dev/null || :
fi
/bin/umount /proc >/dev/null
fi

View File

@ -368,12 +368,14 @@ service at_wini
DEVIO # 21
SDEVIO # 22
VDEVIO # 23
READBIOS # 35
;
pci class
pci class # Match these PCI classes:
1/1 # Mass storage / IDE
1/80 # Mass storage / Other (80 hex)
1/4 # Mass storage / RAID
;
pci device # In addition, match these devices:
1106:3149 # VIA VT6420 RAID (1/4)
1095:3512/1095:6512 # Silicon Image SATA RAID (1/4)
1095:3114/1095:3114 # Silicon Image SATA RAID (1/80)
;
};

View File

@ -93,23 +93,9 @@
*/
#define NR_MEMS 16
/* Click to byte conversions (and vice versa). */
#define HCLICK_SHIFT 4 /* log2 of HCLICK_SIZE */
#define HCLICK_SIZE 16 /* hardware segment conversion magic */
#if CLICK_SIZE >= HCLICK_SIZE
#define click_to_hclick(n) ((n) << (CLICK_SHIFT - HCLICK_SHIFT))
#else
#define click_to_hclick(n) ((n) >> (HCLICK_SHIFT - CLICK_SHIFT))
#endif
#define hclick_to_physb(n) ((phys_bytes) (n) << HCLICK_SHIFT)
#define physb_to_hclick(n) ((n) >> HCLICK_SHIFT)
#define CLICK2ABS(v) ((v) << CLICK_SHIFT)
#define ABS2CLICK(a) ((a) >> CLICK_SHIFT)
#define ABS -999 /* this process means absolute memory */
/* Flag bits for i_mode in the inode. */
#define I_TYPE 0170000 /* this field gives inode type */
#define I_UNIX_SOCKET 0140000 /* unix domain socket */