summaryrefslogtreecommitdiffstats
path: root/sys/i386/isa/ida.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/i386/isa/ida.c')
-rw-r--r--sys/i386/isa/ida.c1786
1 files changed, 0 insertions, 1786 deletions
diff --git a/sys/i386/isa/ida.c b/sys/i386/isa/ida.c
deleted file mode 100644
index 919d365..0000000
--- a/sys/i386/isa/ida.c
+++ /dev/null
@@ -1,1786 +0,0 @@
-/*
- * Copyright (c) 1996, 1997, 1998, 1999
- * Mark Dawson and David James. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice immediately at the beginning of the file, without modification,
- * this list of conditions, and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $Id: ida.c,v 1.1 1999/05/25 19:45:17 julian Exp $
- *
- */
-
-/*
- * Compaq SMART disk array controller driver for FreeBSD.
- * Supports the Compaq SMART-2 and SMART-3 families of disk
- * array controllers.
- *
- */
-
-#include "id.h"
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/kernel.h>
-#include <sys/conf.h>
-#include <sys/errno.h>
-#include <sys/malloc.h>
-#include <sys/buf.h>
-#include <sys/file.h>
-#include <sys/stat.h>
-#include <sys/proc.h>
-#include <sys/sysctl.h>
-#include <i386/isa/isa.h>
-#include <i386/isa/isa_device.h>
-#ifdef DEVFS
-#include <sys/devfsext.h>
-#endif /*DEVFS*/
-/*#include <sys/dkbad.h>*/
-#include <sys/devicestat.h>
-#include <sys/disklabel.h>
-#include <sys/diskslice.h>
-#include <vm/vm.h>
-#include <vm/vm_param.h>
-#include <vm/vm_prot.h>
-#include <vm/pmap.h>
-
-#include <pci.h>
-#include <pci/pcireg.h>
-#include <pci/pcivar.h>
-
-#include <sys/reboot.h>
-extern u_long bootdev;
-
-#define IDA_VERSION 1
-
-#define PAGESIZ 4096
-
-/* IDA wdc vector stealing (cuckoo) control */
-#define IDA_CUCKOO_NEVER 0 /* never steal wdc vectors */
-#define IDA_CUCKOO_ROOTWD 1 /* steal iff rootdev is wd device */
-#define IDA_CUCKOO_ROOTNOTIDA 2 /* steal if rootdev not ida device */
-#define IDA_CUCKOO_ALWAYS 3 /* always steal wdc vectors */
-
-#ifndef IDA_CUCKOO_MODE
-#define IDA_CUCKOO_MODE IDA_CUCKOO_ALWAYS
-#endif
-
-/* IDA PCI controller */
-
-#define PCI_DEVICE_ID_COMPAQ_SMART2P 0xae100e11ul
-#define PCI_CONTROLLER(ctlp) (ctlp->ident == PCI_DEVICE_ID_COMPAQ_SMART2P)
-
-typedef struct ida_pci_reg {
- u_long unknown;
- u_long initiate_fifo;
-#define IDA_PCI_BUSY 1
- u_long complete_fifo;
- u_long interrupt;
-#define IDA_PCI_ENABLE_INTS 1
-#define IDA_PCI_DISABLE_INTS 0
- u_long status;
-#define IDA_PCI_PENDING 1
-#define IDA_PCI_READY 2
-} ida_pci_reg_t;
-
-/* IDA controller register definitions */
-
-#define R_ID0 0xc80 /* id byte 0 */
-#define R_ID1 0xc81 /* id byte 1 */
-#define R_ID2 0xc82 /* id byte 2 */
-#define R_ID3 0xc83 /* id byte 3 */
-#define R_CONF 0xc88 /* global configuration */
-#define R_SYSINT 0xc89 /* system interrupt enable/ctrl */
-#define R_SEM0 0xc8a /* semaphore port 0 */
-#define R_SEM1 0xc8b /* semaphore port 1 */
-#define R_LBELL_E 0xc8c /* local doorbell enable */
-#define R_LBELL_I 0xc8d /* local doorbell int/status */
-#define R_EBELL_E 0xc8e /* EISA doorbell enable */
-#define R_EBELL_I 0xc8f /* EISA doorbell int/status */
-#define R_SUB_ADDR 0xc90 /* submit address */
-#define R_SUB_LEN 0xc94 /* submit cmdlist size */
-#define R_COM_ADDR 0xc98 /* completion address */
-#define R_COM_OFF 0xc9c /* completion request offset */
-#define R_COM_STAT 0xc9e /* completion cmdlist status */
-#define R_INTDEF 0xcc0 /* interrupt definition */
-
-/*
- * BMIC doorbell status codes
- */
-
-#define BMIC_DATA_READY 0x01 /* data ready bit */
-#define BMIC_CHAN_CLEAR 0x02 /* channel clear bit */
-
-
-/* IDA controller command list return status values */
-
-#define IDA_COMPL_OK 0x01 /* command list completed ok */
-#define IDA_NON_FATAL 0x02 /* non-fatal error */
-#define IDA_FATAL 0x04 /* fatal error */
-#define IDA_ABORTED 0x08 /* command list aborted */
-#define IDA_INVAL_REQ 0x10 /* bad request block */
-#define IDA_INVAL_LIST 0x20 /* bad command list */
-#define IDA_AARGH_LIST 0x40 /* totally disastrous command list */
-
-
-/* IDA controller command codes */
-
-#define IDA_GET_DRV_INFO 0x10
-#define IDA_GET_CTL_INFO 0x11
-#define IDA_READ_DATA 0x20
-#define IDA_WRITE_DATA 0x30
-#define IDA_FLUSH_CACHE 0xc2
-
-
-/* Interrupt definition codes */
-
-#define IDA_IRQ_MASK 0xfc
-#define IDA_IRQ_10 0x20
-#define IDA_IRQ_11 0x10
-#define IDA_IRQ_14 0x40
-#define IDA_IRQ_15 0x80
-
-
-/* IDA controller hardware command structure definitions */
-
-typedef u_long physaddr_t;
-
-struct ida_hdr {
- u_long drive:8; /* logical drive */
- u_long priority:8; /* block priority */
- u_long flags:16; /* control flags */
-};
-
-struct ida_req {
- u_long next:16; /* offset of next request */
- u_long command:8; /* command */
- u_long error:8; /* return error code */
- u_long blkno; /* block number */
- u_short bcount; /* block count */
- u_short sgcount; /* number of scatter gather entries */
-
- /* a struct ida_req is followed physically by an array of struct ida_sgb */
-};
-
-struct ida_sgb {
- u_long len; /* length of scatter gather segmmentk */
- physaddr_t addr; /* physical address of block */
-};
-
-
-/* first some handy definitions as FreeBSD gcc doesn't do #pragma pack() */
-
-#define pack_char(name) u_char name[1]
-#define pack_short(name) u_char name[2]
-#define pack_int(name) u_char name[4]
-#define pack_long(name) u_char name[4]
-
-/* ugly, but not inefficient, as it gets evaluated at compile time by gcc */
-
-#define u_unpack(member) ( \
- (sizeof(member) == 1) ? *(u_char *)(member) \
- : (sizeof(member) == 2) ? *(u_short *)(member) \
- : *(u_int *)(member) \
- )
-
-#define s_unpack(member) ( \
- (sizeof(member) == 1) ? *(char *)(member) \
- : (sizeof(member) == 2) ? *(short *)(member) \
- : *(int *)(member) \
- )
-
-/* IDA controller hardware returned data structure definitions */
-
-struct ida_ctl_info {
- pack_char(num_drvs);
- pack_long(signature);
- pack_long(firm_rev);
-};
-
-struct ida_drv_info {
- pack_short(secsize);
- pack_long(secperunit);
- pack_short(ncylinders);
- pack_char(ntracks);
- pack_char(signature);
- pack_char(psectors);
- pack_short(wprecomp);
- pack_char(max_acc);
- pack_char(control);
- pack_short(pcylinders);
- pack_char(ptracks);
- pack_short(landing_zone);
- pack_char(nsectors);
- pack_char(checksum);
- pack_char(mirror);
-};
-
-
-/* IDA driver queue command block */
-
-#define IDA_MAX_SGLEN 32 /* maximum entries in scatter gather list */
-#define IDA_MAX_DRVS_CTLR 8 /* maximum logical drives per controller */
-#define IDA_DEF_PRIORITY 16 /* default priority for command list */
-
-#define IDA_SCSI_TARGET_ID 7
-#define IDA_QCB_MAX 256
-
-struct ida_qcb {
- /* first some hardware specific fields ... */
-
- struct ida_hdr hdr;
- struct ida_req req;
- struct ida_sgb sglist[IDA_MAX_SGLEN];
-
- /* and then some driver queue managment stuff */
-
- u_int flags; /* qcb type */
-#define QCB_FREE 0 /* ready for a new command */
-#define QCB_ACTIVE 1 /* waiting to be sent to the controller */
-#define QCB_SENT 2 /* waiting for interrupt from the controller */
-#define QCB_IMMED 4 /* immediate (non-queued) command */
-#define QCB_IMMED_FAIL 8
- struct ida_qcb *next; /* next ida command block of this type */
- struct ida_qcb *last; /* last ida command block of this type */
- struct buf *buf; /* buf associated with this qcb */
- physaddr_t paddr; /* physical address of this struct */
- struct ida_qcb *nexthash; /* next ida command block with same hash value */
-};
-typedef struct ida_qcb qcb_t;
-
-
-/* IDA driver controller and drive information blocks */
-
-#define QCB_HASH_SIZE 257 /* some suitable prime number */
-#define QCB_HASH(h) ((h) % QCB_HASH_SIZE)
-
-struct ida_drv {
- u_int flags;
-#define ID_INIT 0x0001
-#define ID_WRITEPROT 0x0002
-#define ID_DEV_OPEN 0x0004
- u_int ctl_unit; /* which controller is this drive on */
- u_int drv_unit; /* number of this virtual disk */
- struct ida_drv_info drv_info; /* data from the controller */
- struct diskslices *slices; /* new slice code */
- struct devstat dk_stats; /* devstat entry */
-};
-
-struct ida_ctl {
- u_int ident; /* controller identifier */
- u_int flags;
- u_int iobase;
- u_short inside; /* number of qcbs in the controller */
- u_short max_inside; /* maximum number simulaneously active */
- u_short num_qcbs; /* number of qcbs allocated */
- u_char num_drvs;
- u_char irq;
- u_char com_status; /* status of last completed command list */
- physaddr_t com_addr; /* address of last completed command list */
- u_short com_offset; /* offset of last completed command list */
- qcb_t *freelist; /* linked list of free qcbs */
- qcb_t *send_next; /* doubly-linked list of unsent qcbs */
- qcb_t *send_last; /* because we must treat all jobs equally */
- qcb_t *hashlist[QCB_HASH_SIZE];
-};
-
-extern struct ida_ctl *idadata[NIDA];
-
-
-/* Useful IDA controller IO macro definitions */
-
-#define IDA_DISABLE_INTERRUPT(iobase) outb(iobase + R_SYSINT, 0)
-#define IDA_ENABLE_INTERRUPT(ctlp) outb(ctlp->iobase + R_SYSINT, 1)
-
-#define IDA_SET_READY(ctlp) outb(ctlp->iobase + R_EBELL_E, 1)
-
-#define IDA_DATA_READY(ctlp) ((inb(ctlp->iobase + R_EBELL_I) & 1))
-#define IDA_CHAN_CLEAR(ctlp) ((inb(ctlp->iobase + R_EBELL_I) & 2))
-
-/* enable/disable interrupts on a change of channel clear status (?) */
-
-#define IDA_ENABLE_CHAN(ctlp) \
-outb(ctlp->iobase + R_EBELL_E, inb(ctlp->iobase + R_EBELL_E) | 2)
-#define IDA_DISABLE_CHAN(ctlp) \
-outb(ctlp->iobase + R_EBELL_E, inb(ctlp->iobase + R_EBELL_E) & ~0x2)
-
-/* acknowledge the completion of a command */
-
-#define IDA_ACK_CMD_COM(ctlp) \
-(outb(ctlp->iobase + R_EBELL_I, 1), outb(ctlp->iobase + R_LBELL_I, 2))
-
-/* set submission details for a command list */
-
-#define IDA_SET_SUB_ADDR(ctlp, addr) outl(ctlp->iobase + R_SUB_ADDR, addr)
-#define IDA_SET_SUB_LEN(ctlp, size) outw(ctlp->iobase + R_SUB_LEN, size)
-
-/* get completion details for a command list */
-
-#define IDA_GET_COM_ADDR(ctlp) inl(ctlp->iobase + R_COM_ADDR)
-#define IDA_GET_COM_OFFSET(ctlp) inw(ctlp->iobase + R_COM_OFF)
-#define IDA_GET_COM_STATUS(ctlp) inb(ctlp->iobase + R_COM_STAT)
-
-
-#define IDA_READ_EBELL_I(ctlp) inb(ctlp->iobase + R_EBELL_I)
-#define IDA_READ_EBELL_E(ctlp) inb(ctlp->iobase + R_EBELL_E)
-#define IDA_READ_LBELL_I(ctlp) inb(ctlp->iobase + R_LBELL_I)
-#define IDA_SET_EBELL_I(ctlp, n) outb(ctlp->iobase + R_EBELL_I, n)
-#define IDA_SET_LBELL_I(ctlp, n) outb(ctlp->iobase + R_LBELL_I, n)
-
-#define JOB_SUCCESS 0
-#define JOB_FAILURE 1
-#define JOB_ABORTED 2
-
-/* debugging aids */
-
-#ifdef IDADEBUG
-# define IDA_MAXQCBS (1<<0)
-# define IDA_SHOWQCBS (1<<1)
-# define IDA_SHOWSUBS (1<<2)
-# define IDA_SHOWINTS (1<<3)
-# define IDA_SHOWCMDS (1<<4)
-# define IDA_SHOWMISC (1<<5)
-void ida_print_qcb(qcb_t *qcbp);
-void ida_print_active_qcb(int unit);
-static int ida_debug = 0;
-SYSCTL_INT(_debug, OID_AUTO, ida_debug, CTLFLAG_RW, &ida_debug, 0, "");
-#endif
-
-static int ida_soft_errors = 0;
-SYSCTL_INT(_debug, OID_AUTO, ida_soft_errors,
- CTLFLAG_RW, &ida_soft_errors, 0, "");
-
-/* EISA probe and board identification definitions */
-
-#define MAX_EISA_SLOT 16
-#define IDA_EISA_PROD_ID 0x40
-
-union eisa_id {
- u_int value;
- struct {
- u_int rev:8;
- u_int prod:8;
- u_int mfr2:5;
- u_int mfr1:5;
- u_int mfr0:5;
- } split;
-};
-
-
-/* test the manufacturer ID within an EISA board ID */
-
-#define EISA_MFR_EQ(ident, mfr) ( \
- (ident).split.mfr0 + '@' == (mfr)[0] && \
- (ident).split.mfr1 + '@' == (mfr)[1] && \
- (ident).split.mfr2 + '@' == (mfr)[2] \
- )
-
-/* generates a list of EISA board ID values, suitable for a printf */
-
-#define EISA_ID_LIST(ident) \
-(ident).split.mfr0 + '@', \
- (ident).split.mfr1 + '@', \
- (ident).split.mfr2 + '@', \
- (ident).split.prod, \
- (ident).split.rev
-
-extern void DELAY(int millisecs);
-
-/* FreeBSD IDA driver forward function definitions */
-
-static d_open_t idopen;
-static d_read_t idread;
-static d_write_t idwrite;
-static d_close_t idclose;
-static d_strategy_t idstrategy;
-static d_ioctl_t idioctl;
-static d_dump_t iddump;
-static d_psize_t idsize;
-
-static pci_inthand_t idaintr;
-
-static const char *ida_pci_probe(pcici_t tag, pcidi_t type);
-static void ida_pci_attach(pcici_t config_id, int unit);
-
-static int ida_eisa_probe __P((struct isa_device *dev));
-static int ida_eisa_attach __P((struct isa_device *dev));
-static int ida_poll __P((int unit, int wait));
-
-static void idaminphys __P((struct buf *bp));
-static void ida_start __P((int unit));
-
-static int ida_get_ctl_info(int unit);
-static int ida_attach_drives(int unit);
-void ida_done(int cntlr, qcb_t *qcbp, int state);
-static void ida_queue_buf(int cntlr, struct buf *bp);
-static void ida_newqueue(int cntlr);
-static qcb_t *ida_dequeue(int cntlr);
-static void ida_enqueue(int cntlr, qcb_t *qcbp);
-static int ida_submit(int unit, qcb_t *qcbp, int size);
-static int ida_submit_wait(int unit, qcb_t *qcbp, int size);
-static qcb_t *ida_get_qcb(int unit);
-static void ida_free_qcb(int unit, qcb_t *qcbp);
-static qcb_t *ida_qcb_phys_kv(struct ida_ctl *ida, physaddr_t ida_qcb_phys);
-
-static struct cdevsw id_cdevsw;
-
-struct isa_driver idadriver = {
- ida_eisa_probe,
- ida_eisa_attach,
- "ida"
-};
-
-static u_long ida_pci_count;
-
-static struct pci_device ida_pci_driver = {
- "ida",
- ida_pci_probe,
- ida_pci_attach,
- &ida_pci_count
-};
-
-DATA_SET (pcidevice_set, ida_pci_driver);
-
-/* definitions for stealing wd driver's vectors */
-
-#define ID_BDMAJ 29
-#define ID_CDMAJ 109
-#define WD_BDMAJ 0
-#define WD_CDMAJ 3
-
-struct isa_driver wdcdriver;
-static int stub_probe __P((struct isa_device *dev));
-static int stub_attach __P((struct isa_device *dev));
-
-static struct isa_driver nodriver = {
- stub_probe,
- stub_attach,
- "stub"
-};
-
-/* steal the wdc driver's vectors if we have booted off a wd device */
-
-static
-void
-ida_cuckoo_wdc(void)
-{
- int cuckoo = IDA_CUCKOO_MODE;
- int steal = 0;
- char *mode;
- int major = B_TYPE(bootdev);
-
- if (cuckoo == IDA_CUCKOO_NEVER) {
- mode = "never";
- } else if (cuckoo == IDA_CUCKOO_ROOTWD) {
- mode = "rootwd";
- steal = (major == WD_BDMAJ);
- } else if (cuckoo == IDA_CUCKOO_ROOTNOTIDA) {
- mode = "notida";
- /* check for magic value of 3 rather than ID_BDMAJ as boot code
- * pretends we are a wt device (not normally bootable)
- */
- steal = (major != 3);
- } else {
- mode = "always";
- steal = 1;
- }
-
- printf("ida: wdc vector stealing %s (mode = %s, boot major = %d)\n",
- (steal ? "on" : "off"), mode, major);
- if (!steal) return;
-
- /* OK - we have a controller, so steal wd driver's vectors */
- wdcdriver = nodriver;
- bdevsw[WD_BDMAJ]->d_open = cdevsw[WD_CDMAJ]->d_open = idopen;
- bdevsw[WD_BDMAJ]->d_close = cdevsw[WD_CDMAJ]->d_close = idclose;
- bdevsw[WD_BDMAJ]->d_read = cdevsw[WD_CDMAJ]->d_read = idread;
- bdevsw[WD_BDMAJ]->d_write = cdevsw[WD_CDMAJ]->d_write = idwrite;
- bdevsw[WD_BDMAJ]->d_strategy = cdevsw[WD_CDMAJ]->d_strategy = idstrategy;
- bdevsw[WD_BDMAJ]->d_ioctl = cdevsw[WD_CDMAJ]->d_ioctl = idioctl;
- bdevsw[WD_BDMAJ]->d_dump = iddump;
- bdevsw[WD_BDMAJ]->d_psize = idsize;
- return;
-}
-
-static struct ida_ctl *idadata[NIDA]; /* controller structures */
-static struct ida_drv *id_drive[NID]; /* table of drives */
-static int id_unit = 0; /* number of drives found */
-
-/* general purpose data buffer for 'special' IDA driver commands */
-
-union ida_buf {
- char pad[512];
- struct ida_ctl_info ctl;
- struct ida_drv_info drv;
-} ida_buf;
-
-static int
-stub_probe(struct isa_device *dev)
-{
- return 0;
-}
-
-static int
-stub_attach(struct isa_device *dev)
-{
- return 0;
-}
-
-const char *
-ida_pci_probe(pcici_t tag, pcidi_t type)
-{
- switch (type) {
- case PCI_DEVICE_ID_COMPAQ_SMART2P:
- return "Compaq SMART-2/P array controller";
- break;
- default:
- break;
- }
- return NULL;
-}
-
-static void
-ida_pci_attach(pcici_t config_id, int unit)
-{
- ida_pci_reg_t *reg;
- struct ida_ctl *ctlp;
- u_long id;
- vm_offset_t paddr, vaddr;
-
- id = pci_conf_read(config_id, PCI_ID_REG);
- switch (id) {
- case PCI_DEVICE_ID_COMPAQ_SMART2P:
- break;
- default:
- break;
- }
-
- if (!pci_map_mem(config_id, 0x14, &vaddr, &paddr)) {
- printf("ida: map failed.\n");
- return;
- }
-
- /* allocate and initialise a storage area for this controller */
- if (idadata[unit]) {
- printf("ida%d: controller structure already allocated\n", unit);
- return;
- }
- if ((ctlp = malloc(sizeof(struct ida_ctl), M_TEMP, M_NOWAIT)) == NULL) {
- printf("ida%d: unable to allocate controller structure\n", unit);
- return;
- }
-
- idadata[unit] = ctlp;
- bzero(ctlp, sizeof(struct ida_ctl));
- ctlp->ident = id;
- ctlp->iobase = vaddr;
-
- /* Install the interrupt handler. */
- if (!pci_map_int (config_id, idaintr, (void *)unit, &bio_imask)) {
- printf ("ida%d: failed to assign an interrupt handler\n", unit);
- free((caddr_t)ctlp, M_DEVBUF);
- idadata[unit] = 0;
- return;
- }
-
- if (!(ida_get_ctl_info(unit) && ida_attach_drives(unit))) {
- return;
- }
-
- reg = (ida_pci_reg_t *) vaddr;
- reg->interrupt = IDA_PCI_ENABLE_INTS;
- ida_cuckoo_wdc();
- return;
-}
-
-int
-ida_eisa_probe(struct isa_device *dev)
-{
- static u_int ida_used = 0;
- u_int slot;
- u_int port;
- u_char intdef;
- u_char irq;
- int unit = dev->id_unit;
- union eisa_id ident;
- struct ida_ctl *ctlp;
-
- if (dev->id_iobase) {
- /* check out the configured iobase if given one */
- slot = dev->id_iobase / 0x1000;
- if (slot == 0 || slot > MAX_EISA_SLOT) {
- printf("ida: port address (0x%x) out of range\n", dev->id_iobase);
- return 0;
- }
- } else {
- /* otherwise, search from the beginning for an unused slot to check out */
- slot = 1;
- }
-
- while (1) {
- while (ida_used & (1 << slot)) {
- if (slot++ == MAX_EISA_SLOT) return 0;
- }
-
- ida_used |= (1 << slot);
- port = slot * 0x1000;
-
- /* read the EISA identification bytes */
- ident.value = inb(port + R_ID0);
- ident.value <<= 8;
- ident.value |= inb(port + R_ID1);
- ident.value <<= 8;
- ident.value |= inb(port + R_ID2);
- ident.value <<= 8;
- ident.value |= inb(port + R_ID3);
-
- /* check that the card is the right type ? */
- if (EISA_MFR_EQ(ident, "CPQ") && ident.split.prod == IDA_EISA_PROD_ID) {
- break;
- }
-
- /* if we were config'ed with an iobase, then don't probe any more slots */
- if (dev->id_iobase) return 0;
- }
-
- /* disable interrupts and find out what interrupt this controller uses */
- IDA_DISABLE_INTERRUPT(port);
-
- intdef = inb(port + R_INTDEF);
- switch (intdef & IDA_IRQ_MASK) {
- case IDA_IRQ_10:
- irq = 10;
- break;
-
- case IDA_IRQ_11:
- irq = 11;
- break;
-
- case IDA_IRQ_14:
- irq = 14;
- break;
-
- case IDA_IRQ_15:
- irq = 15;
- break;
-
- default:
- printf("ida: slot %d bogus interrupt setting (0x%02x)\n", slot, intdef);
- return 0;
- }
- dev->id_irq = (1 << irq);
- dev->id_drq = -1;
-
- /* allocate and initialise a storage area for this controller */
- if (idadata[unit]) {
- printf("ida%d: controller structure already allocated\n", unit);
- return 0;
- }
- if ((ctlp = malloc(sizeof(struct ida_ctl), M_TEMP, M_NOWAIT)) == NULL) {
- printf("ida%d: unable to allocate controller structure\n", unit);
- return 0;
- }
- idadata[unit] = ctlp;
-
- bzero(ctlp, sizeof(struct ida_ctl));
- ctlp->iobase = dev->id_iobase = port;
- ctlp->ident = ident.value;
- ctlp->irq = irq;
-
- if (ida_get_ctl_info(unit) == 0) {
- return 0;
- }
-
- /* return range of io ports used */
- return 0x1000;
-}
-
-int
-ida_get_ctl_info(int unit)
-{
- struct ida_ctl *ctlp = idadata[unit];
- qcb_t qcb;
- qcb_t *qcbp = &qcb;
-
- ida_newqueue(unit);
- /* controller capacity statistics */
- ctlp->inside = 0;
- ctlp->max_inside = 0;
-
- /* ask the controller to tell us about itself with an IDA_GET_CTL_INFO */
- bzero(qcbp, sizeof(qcb_t));
- qcbp->paddr = vtophys(qcbp);
- if (PCI_CONTROLLER(ctlp)) {
- qcbp->hdr.priority = 0x00;
- qcbp->hdr.flags = 0x24;
- } else {
- qcbp->hdr.priority = IDA_DEF_PRIORITY;
- qcbp->hdr.flags = 0x12;
- }
- qcbp->req.command = IDA_GET_CTL_INFO;
- qcbp->req.bcount = 1;
- qcbp->req.sgcount = 1;
- qcbp->sglist[0].len = sizeof(ida_buf);
- qcbp->sglist[0].addr = vtophys(&ida_buf);
-
- if (ida_submit_wait(unit, qcbp, sizeof(struct ida_qcb))) {
- printf("ida%d: idasubmit failed on IDA_GET_CTL_INFO\n", unit);
- return 0;
- }
-
- if (!PCI_CONTROLLER(ctlp)) {
- if (ctlp->com_status != IDA_COMPL_OK) {
- printf("ida%d: bad status 0x%02x from IDA_GET_CTL_INFO\n",
- unit, ctlp->com_status);
- return 0;
- }
- }
-
- /* got the information at last, print it and note the number of drives */
- printf("ida%d: drvs=%d firm_rev=%c%c%c%c\n", unit,
- u_unpack(ida_buf.ctl.num_drvs), ida_buf.ctl.firm_rev[0],
- ida_buf.ctl.firm_rev[1], ida_buf.ctl.firm_rev[2],
- ida_buf.ctl.firm_rev[3]);
- ctlp->num_drvs = u_unpack(ida_buf.ctl.num_drvs);
-
- return 1;
-}
-
-int
-ida_attach_drives(int cntlr)
-{
- struct ida_ctl *ctlp = idadata[cntlr];
- qcb_t qcb;
- qcb_t *qcbp = &qcb;
- struct ida_drv *drv;
- int drive;
- int unit;
-
- /* prepare to interrogate the drives */
- bzero(qcbp, sizeof(qcb_t));
- qcbp->req.command = IDA_GET_DRV_INFO;
- qcbp->paddr = vtophys(qcbp);
- if (PCI_CONTROLLER(ctlp)) {
- qcbp->hdr.priority = 0x00;
- qcbp->hdr.flags = 0x24;
- } else {
- qcbp->hdr.priority = IDA_DEF_PRIORITY;
- qcbp->hdr.flags = 0x12;
- }
- qcbp->req.bcount = 1;
- qcbp->req.sgcount = 1;
- qcbp->sglist[0].len = sizeof(ida_buf);
- qcbp->sglist[0].addr = vtophys(&ida_buf);
-
- for (drive = 0 ; drive < ctlp->num_drvs ; drive++) {
- qcbp->hdr.drive = drive;
-
- if (ida_submit_wait(cntlr, qcbp, sizeof(struct ida_qcb))) {
- printf("ida%d: ida_submit_wait failed on IDA_GET_DRV_INFO\n", cntlr);
- return 0;
- }
-
- if (!PCI_CONTROLLER(ctlp)) {
- if (ctlp->com_status != IDA_COMPL_OK) {
- printf("ida%d: bad status 0x%02x from IDA_GET_DRV_INFO\n",
- cntlr, ctlp->com_status);
- return 0;
- }
- }
-
- if ((drv = malloc(sizeof(struct ida_drv), M_TEMP, M_NOWAIT)) == NULL) {
- printf("ida%d: unable to allocate drive structure\n", cntlr);
- return 0;
- }
-
- bzero(drv, sizeof(struct ida_drv));
- drv->ctl_unit = cntlr;
- drv->drv_unit = drive;
- drv->drv_info = ida_buf.drv;
- drv->flags |= ID_INIT;
-
- unit = id_unit;
- id_unit++; /* XXX unsure if this is the right way to do things */
- id_drive[unit] = drv;
-
- printf("ida%d: unit %d (id%d): <%s>\n",
- cntlr, drive, unit, "Compaq Logical Drive");
- printf("id%d: %luMB (%lu total sec), ",
- unit,
- (u_long)(u_unpack(drv->drv_info.secperunit) / 2048)
- * (u_unpack(drv->drv_info.secsize) / 512),
- (u_long)u_unpack(drv->drv_info.secperunit));
- printf("%lu cyl, %lu head, %lu sec, bytes/sec %lu\n",
- (u_long)u_unpack(drv->drv_info.ncylinders),
- (u_long)u_unpack(drv->drv_info.ntracks),
- (u_long)u_unpack(drv->drv_info.nsectors),
- (u_long)u_unpack(drv->drv_info.secsize));
-
- /*
- * Export the drive to the devstat interface.
- */
- devstat_add_entry(&drv->dk_stats, "id",
- unit, (u_int32_t)drv->drv_info.secsize,
- DEVSTAT_NO_ORDERED_TAGS,
- DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_OTHER);
-
-#ifdef IDADEBUG
- if (ida_debug & IDA_SHOWMISC) {
- printf("ida%d: drive %d secsize=%d secperunit=%d ncylinders=%d ntracks=%d\n",
- unit,
- drive,
- u_unpack(ida_buf.drv.secsize),
- u_unpack(ida_buf.drv.secperunit),
- u_unpack(ida_buf.drv.ncylinders),
- u_unpack(ida_buf.drv.ntracks));
- printf(" signature=0x%02x psectors=%d wprecomp=%d max_acc=%d control=0x%02x\n",
- u_unpack(ida_buf.drv.signature),
- u_unpack(ida_buf.drv.psectors),
- u_unpack(ida_buf.drv.wprecomp),
- u_unpack(ida_buf.drv.max_acc),
- u_unpack(ida_buf.drv.control));
- printf(" pcylinders=%d ptracks=%d landing_zone=%d nsectors=%d checksum=0x%02x\n",
- u_unpack(ida_buf.drv.pcylinders),
- u_unpack(ida_buf.drv.ptracks),
- u_unpack(ida_buf.drv.landing_zone),
- u_unpack(ida_buf.drv.nsectors),
- u_unpack(ida_buf.drv.checksum));
- }
-#endif
- }
-
- return 1;
-}
-
-/* Attach all the sub-devices we can find. */
-int
-ida_eisa_attach(struct isa_device *dev)
-{
- int cntlr = dev->id_unit;
- struct ida_ctl *ctlp = idadata[cntlr];
-
- if (ida_attach_drives(cntlr)) {
- IDA_ENABLE_INTERRUPT(ctlp);
- IDA_SET_READY(ctlp);
- ida_cuckoo_wdc();
- return 1;
- } else {
- return 0;
- }
-}
-
-/*
- * Initialize a drive.
- */
-int
-idopen(dev_t dev, int flags, int fmt, struct proc *p)
-{
- struct ida_drv *drv;
- int part = dkpart(dev);
- int unit = dkunit(dev);
- struct disklabel label;
- int err;
-
- if (unit >= NID || part >= MAXPARTITIONS) /* bounds check */
- return(ENXIO);
-
- drv = id_drive[unit];
- if (!drv || !(drv->flags & ID_INIT)) /* drive not initialised */
- return(ENXIO);
-
- drv->flags |= ID_DEV_OPEN;
-
- /* knock up a label for the whole disk. */
- bzero(&label, sizeof label);
- label.d_secsize = u_unpack(drv->drv_info.secsize);
- label.d_nsectors = u_unpack(drv->drv_info.nsectors);
- label.d_ntracks = u_unpack(drv->drv_info.ntracks);
- label.d_ncylinders = u_unpack(drv->drv_info.ncylinders);
- label.d_secpercyl =
- u_unpack(drv->drv_info.ntracks) * u_unpack(drv->drv_info.nsectors);
- if (label.d_secpercyl == 0)
- label.d_secpercyl = 100; /* prevent accidental division by zero */
- label.d_secperunit = u_unpack(drv->drv_info.secperunit);
-
- /* Initialize slice tables. */
- if ((err = dsopen("id", dev, fmt, 0, &drv->slices, &label, idstrategy,
- (ds_setgeom_t *)NULL, &id_cdevsw)) == NULL) {
- return 0;
- }
-
- if (!dsisopen(drv->slices)) {
- drv->flags &= ~ID_DEV_OPEN;
- }
- return err;
-}
-
-/* ARGSUSED */
-int
-idclose(dev_t dev, int flags, int fmt, struct proc *p)
-{
- struct ida_drv *drv;
- int part = dkpart(dev);
- int unit = dkunit(dev);
-
- if (unit >= NID || part >= MAXPARTITIONS) /* bounds check */
- return(ENXIO);
-
- drv = id_drive[unit];
- dsclose(dev, fmt, drv->slices);
- if (!dsisopen(drv->slices)) {
- drv->flags &= ~ID_DEV_OPEN;
- }
- return 0;
-}
-
-
-
-int
-idioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
-{
- struct ida_drv *drv;
- int part = dkpart(dev);
- int unit = dkunit(dev);
- int err;
-
- if (unit >= NID || part >= MAXPARTITIONS ||
- !(drv = id_drive[unit]) || !(drv->flags & ID_INIT)) /* sanity check */
- return(ENXIO);
-
- err = dsioctl("id", dev, cmd, addr, flag, &drv->slices,
- idstrategy, (ds_setgeom_t *)NULL);
-
- if (err != -1)
- return (err);
-
- if (dkpart(dev) != RAW_PART)
- return (ENOTTY);
-
- return (0);
-}
-static int
-idread(dev_t dev, struct uio *uio, int ioflag)
-{
- return (physio(idstrategy, NULL, dev, 1, minphys, uio));
-}
-
-static int
-idwrite(dev_t dev, struct uio *uio, int ioflag)
-{
- return (physio(idstrategy, NULL, dev, 0, minphys, uio));
-}
-
-
-/* Read/write routine for a buffer. Finds the proper unit, range checks
- * arguments, and schedules the transfer. Does not wait for the transfer
- * to complete. Multi-page transfers are supported. All I/O requests must
- * be a multiple of a sector in length.
- */
-void
-idstrategy(struct buf *bp)
-{
- int unit = dkunit(bp->b_dev);
- struct ida_drv *drv;
- int opri;
-
- if (unit >= NID) {
- printf("ida: unit out of range\n");
- bp->b_error = EINVAL;
- goto bad;
- }
-
- if (!(drv = id_drive[unit]) || !(drv->flags & ID_INIT)) {
- printf("id%d: drive not initialised\n", unit);
- bp->b_error = EINVAL;
- goto bad;
- }
-
- if (bp->b_blkno < 0) {
- printf("id%d: negative block requested\n", unit);
- bp->b_error = EINVAL;
- goto bad;
- }
-
- if (bp->b_bcount % DEV_BSIZE != 0) { /* bounds check */
- printf("id%d: count (%lu) not a multiple of a block\n",
- unit, bp->b_bcount);
- bp->b_error = EINVAL;
- goto bad;
- }
-
- idaminphys(bp); /* adjust the transfer size */
-
- /* "soft" write protect check */
- if ((drv->flags & ID_WRITEPROT) && (bp->b_flags & B_READ) == 0) {
- bp->b_error = EROFS;
- goto bad;
- }
-
- /* If it's a null transfer, return immediately */
- if (bp->b_bcount == 0) {
- goto done;
- }
-
- if (dscheck(bp, drv->slices) <= 0) {
- goto done;
- }
-
- opri = splbio();
- ida_queue_buf(unit, bp);
- devstat_start_transaction(&drv->dk_stats);
- ida_start(drv->ctl_unit); /* hit the appropriate controller */
- splx(opri);
-
- return /*0*/;
-
-bad:
- bp->b_flags |= B_ERROR;
-
-done:
- /* correctly set the buf to indicate a completed xfer */
- bp->b_resid = bp->b_bcount;
- biodone(bp);
- return /*0*/;
-}
-
-
-void
-idaminphys(bp)
-struct buf *bp;
-{
- /* assumes each page requires an sgb entry */
- int max = (IDA_MAX_SGLEN - 1) * PAGESIZ;
- if (bp->b_bcount > max) {
- bp->b_bcount = max;
- }
-}
-
-
-/* Get a free qcb.
- * If there are none, see if we can allocate a new one.
- * If so, put it in the hash table too,
- * otherwise either return an error or sleep.
- */
-static qcb_t *
-ida_get_qcb(int unit)
-{
- struct ida_ctl *ida = idadata[unit];
- unsigned opri = 0;
- qcb_t *qcbp;
- int hashnum;
-
- opri = splbio();
-
- /* if the freelist is empty - create a qcb until limit is reached */
- while (!(qcbp = ida->freelist)) {
- if (ida->num_qcbs < IDA_QCB_MAX) {
- qcbp = (qcb_t *)malloc(sizeof(qcb_t), M_TEMP, M_NOWAIT);
- if (qcbp) {
- bzero(qcbp, sizeof(qcb_t));
- ida->num_qcbs++;
- qcbp->flags = QCB_ACTIVE;
-#ifdef IDADEBUG
- if (ida_debug & IDA_SHOWQCBS)
- printf("ida_get_qcb%d: qcb %d created\n",
- unit, ida->num_qcbs);
-#endif
- /* Put in the phystokv hash table. */
- /* Never gets taken out. */
- qcbp->paddr = vtophys(qcbp);
- hashnum = QCB_HASH(qcbp->paddr);
- qcbp->nexthash = ida->hashlist[hashnum];
- ida->hashlist[hashnum] = qcbp;
- } else {
- printf("ida%d: Can't malloc QCB\n", unit);
- } goto gottit;
- } else {
- /* reached maximum allocation of qcbs - sleep until one is freed */
- tsleep((caddr_t)&ida->freelist, PRIBIO, "idaqcb", 0);
- }
- } if (qcbp) {
- /* qet the qcb from from the (non-empty) free list */
- ida->freelist = qcbp->next;
- qcbp->flags = QCB_ACTIVE;
- }
-gottit:
- splx(opri);
-
-#ifdef IDADEBUG
- if (ida_debug & IDA_SHOWQCBS)
- printf("ida_get_qcb%d: returns 0x%x\n", unit, qcbp);
-#endif
-
- return (qcbp);
-}
-
-
-/* Return a qcb to the free list */
-static void
-ida_free_qcb(int unit, qcb_t *qcbp)
-{
- unsigned int opri = 0;
- struct ida_ctl *ida = idadata[unit];
-
-#ifdef IDADEBUG
- if (ida_debug & IDA_SHOWQCBS)
- printf("ida_free_qcb%d: freeing 0x%x\n", unit, qcbp);
-#endif
-
- opri = splbio();
-
- qcbp->next = ida->freelist;
- ida->freelist = qcbp;
- qcbp->flags = QCB_FREE;
-
- /* if the free list was empty, wakeup anyone sleeping */
-
- if (!qcbp->next) {
-#ifdef IDADEBUG
- if (ida_debug & IDA_SHOWQCBS)
- printf("ida_free_qcb%d: about to wakeup 0x%x queue\n",
- unit, &ida->freelist);
-#endif
- wakeup((caddr_t)&ida->freelist);
- }
-
- splx(opri);
-}
-
-/* Find the ida_qcb having a given physical address */
-qcb_t *
-ida_qcb_phys_kv(ida, ida_qcb_phys)
-struct ida_ctl *ida;
-physaddr_t ida_qcb_phys;
-{
- int hash = QCB_HASH(ida_qcb_phys);
- qcb_t *qcbp = ida->hashlist[hash];
-
- while (qcbp) {
- if (qcbp->paddr == ida_qcb_phys)
- break;
- qcbp = qcbp->nexthash;
- }
-
-#ifdef IDADEBUG
- if (ida_debug & IDA_SHOWQCBS)
- printf("ida?: ida_qcb_phys_kv(0x%x) = 0x%x\n", ida_qcb_phys, qcbp);
-#endif
-
- return qcbp;
-}
-
-void
-ida_queue_buf(int unit, struct buf *bp)
-{
- struct ida_drv *drv = id_drive[unit];
- int cntlr = drv->ctl_unit;
- qcb_t *qcbp = ida_get_qcb(cntlr); /* may cause us to wait */
- struct ida_ctl *ida = idadata[cntlr];
- unsigned int datalen = bp->b_bcount;
- int thiskv = (int)bp->b_data;
- physaddr_t thisphys = vtophys(thiskv);
- int nsgb = 0; /* number of scatter/gather blocks used */
- struct ida_sgb *sg = &(qcbp->sglist[0]);
-
- /* fill in the qcb command header */
-
- if (PCI_CONTROLLER(ida)) {
- qcbp->hdr.priority = 0x00;
- qcbp->hdr.flags = 0x24;
- } else {
- qcbp->hdr.priority = IDA_DEF_PRIORITY;
- qcbp->hdr.flags = 0x10;
- }
- qcbp->hdr.drive = drv->drv_unit; /* logical drive number */
- qcbp->buf = bp; /* the buf this command came from */
-
- /* set up the scatter-gather list in the qcb */
-
- while ((datalen) && (nsgb < IDA_MAX_SGLEN)) {
- int bytes_this_seg = 0;
- physaddr_t nextphys;
-
- /* put in the base address */
- sg->addr = thisphys;
-
- /* do it at least once */
- nextphys = thisphys;
- while ((datalen) && (thisphys == nextphys)) {
- int bytes_this_page;
-
- /* This page is contiguous (physically) with the the last, */
- /* just extend the length */
-
- /* how far to the end of the page ... */
- nextphys = (thisphys & (~(PAGESIZ - 1))) + PAGESIZ;
- bytes_this_page = nextphys - thisphys;
- /* ... or to the end of the data */
- bytes_this_page = min(bytes_this_page, datalen);
- bytes_this_seg += bytes_this_page;
- datalen -= bytes_this_page;
-
- /* get ready for the next page */
- thiskv = (thiskv & (~(PAGESIZ - 1))) + PAGESIZ;
- if (datalen)
- thisphys = vtophys(thiskv);
- }
-
- /* next page isn't contiguous, finish the seg */
- sg->len = bytes_this_seg;
- sg++;
- nsgb++;
- }
-
- if (datalen) { /* still data => command block too small */
- printf("ida_queue_buf%d: more than %d scatter/gather blocks needed\n",
- cntlr, IDA_MAX_SGLEN);
- bp->b_error = EIO;
- bp->b_flags |= B_ERROR;
- biodone(bp);
- return;
- }
-
- /* fill-in the I/O request block */
-
- qcbp->req.error = 0;
- qcbp->req.next = 0;
- qcbp->req.blkno = bp->b_pblkno;
- qcbp->req.bcount = bp->b_bcount >> 9;
- qcbp->req.sgcount = nsgb;
- qcbp->req.command = (bp->b_flags & B_READ ? IDA_READ_DATA : IDA_WRITE_DATA);
-
-#ifdef IDADEBUG
- if (ida_debug & IDA_SHOWQCBS) {
- printf("ida_rw%d: queuing:\n", cntlr);
- ida_print_qcb(qcbp);
- }
-#endif
-
- /* queue for submission to the controller */
- ida_enqueue(cntlr, qcbp);
-}
-
-
-void
-ida_start(int cntlr)
-{
- struct ida_ctl *ida = idadata[cntlr];
- qcb_t *qcbp;
- int count = 0;
- int opri = splbio();
-
- if (!ida->send_next) { /* check there is a job in the queue */
- splx(opri);
- return;
- }
-
- if (PCI_CONTROLLER(ida)) {
- ida_pci_reg_t *reg = (ida_pci_reg_t *)ida->iobase;
- u_int fifo = reg->initiate_fifo;
- if (fifo == 1) {
- splx(opri);
- return; /* not sent - must try again later */
- }
-
- /* submit upto 16 jobs at once into the initiate fifo */
- while (count < 16 && (fifo = reg->initiate_fifo) != 1
- && (qcbp = ida_dequeue(cntlr))) {
- reg->initiate_fifo = qcbp->paddr;
- qcbp->flags = QCB_SENT;
- ida->inside++;
- count++;
- }
- } else {
-
- if (!IDA_CHAN_CLEAR(ida)) {
- IDA_ENABLE_CHAN(ida);
- splx(opri);
- return;
- }
-
- qcbp = ida_dequeue(cntlr);
-
-#ifdef IDADEBUG
- if (ida_debug & IDA_SHOWQCBS)
- printf("ida%d: ida_start: sending 0x%x\n", cntlr, qcbp);
-#endif
-
- IDA_SET_EBELL_I(ida, 2);
- IDA_SET_SUB_ADDR(ida, qcbp->paddr); /* physical address of this qcb */
- IDA_SET_SUB_LEN(ida, sizeof(qcb_t));
- IDA_SET_LBELL_I(ida, 1);
-
- qcbp->flags = QCB_SENT;
- ida->inside++;
- count++;
- }
-
- if (ida->inside > ida->max_inside) {
- ida->max_inside = ida->inside; /* new maximum */
- splx(opri);
-
-#ifdef IDADEBUG
- if (ida_debug & IDA_MAXQCBS)
- printf("ida%d: qcbs %d/%d\n", cntlr, ida->inside, ida->num_qcbs);
-#endif
- } else {
- splx(opri);
- }
-
-#ifdef IDADEBUG
- if ((ida_debug & IDA_SHOWSUBS) && count > 1)
- printf("ida%d: %d jobs submitted (queue %s).\n",
- cntlr, count, ida->send_next ? "not emptied" : "emptied");
-#endif
-}
-
-void
-ida_newqueue(int cntlr)
-{
- struct ida_ctl *ida = idadata[cntlr];
- ida->send_next = 0;
- ida->send_last = 0;
-}
-
-qcb_t *
-ida_dequeue(int cntlr)
-{
- struct ida_ctl *ida = idadata[cntlr];
- qcb_t *qcbp = ida->send_next; /* who is next? */
-
- if (qcbp) { /* queue is not empty */
- qcb_t* nextp = qcbp->next;
-
- if (nextp) { /* more than one element in the queue */
- nextp->last = 0; /* we are the first */
- ida->send_next = nextp; /* hence first to go */
- } else { /* exactly one element in the queue */
- ida->send_last = ida->send_next = 0;
- }
- }
-
- return qcbp;
-}
-
-static void
-ida_enqueue(int cntlr, qcb_t *qcbp)
-{
- struct ida_ctl *ida = idadata[cntlr];
- qcb_t *lastp = ida->send_last; /* who is last? */
- int opri = splbio();
-
- if (lastp) { /* if the queue is not empty */
- lastp->next = qcbp; /* then we go after the last */
- } else { /* if the queue was empty */
- ida->send_next = qcbp; /* then we go next */
- }
-
- qcbp->last = lastp; /* we follow the last */
- qcbp->next = 0; /* and nothing follows us */
-
- ida->send_last = qcbp; /* we go last */
- splx(opri);
-}
-
-void
-idaintr(void *arg)
-{
- int cntlr = (int)arg;
- qcb_t *qcbp;
- struct ida_ctl *ida = idadata[cntlr];
- u_char status;
- physaddr_t paddr, paddr1; /* physical address of the qcb */
- int offset; /* qcb offset */
- u_char cstat; /* job status */
-
- if (PCI_CONTROLLER(ida)) { /*pci:*/
- ida_pci_reg_t *reg = (ida_pci_reg_t *)ida->iobase;
- int status = reg->status;
-#ifdef IDADEBUG
- if (ida_debug & IDA_SHOWINTS)
- printf("ida%d: idaintr: status=%x (before complete)\n"
- , cntlr, status);
-#endif
- while (status & IDA_PCI_PENDING) {
- paddr1 = reg->complete_fifo;
- paddr = paddr1 & ~3;
- qcbp = ida_qcb_phys_kv(ida, paddr);
-#ifdef IDADEBUG
- if (ida_debug & IDA_SHOWQCBS) {
- printf("ida%d: idaintr: qcb(%x) completed\n", cntlr, qcbp);
- ida_print_qcb(qcbp);
- }
-#endif
- if (qcbp) {
- if (qcbp->req.error & 3) ida_soft_errors++;
- ida_done(cntlr, qcbp, (qcbp->req.error>>2) ? JOB_FAILURE : JOB_SUCCESS);
- } else {
- printf("ida%d: idaintr: completion (%x) ignored\n", cntlr, paddr1);
- }
- status = reg->status;
- }
-#ifdef IDADEBUG
- if (ida_debug & IDA_SHOWINTS)
- printf("ida%d: idaintr: status=%x (before initiate)\n"
- , cntlr, status);
-#endif
- if (status & IDA_PCI_READY) {
- ida_start(cntlr);
- }
- } else {
- while(1) {
- status = IDA_READ_EBELL_I(ida) & IDA_READ_EBELL_E(ida);
-
-#ifdef IDADEBUG
- if (ida_debug & IDA_SHOWINTS)
- printf("ida%d: idaintr: status = 0x%x\n", cntlr, status);
-#endif
-
- if ((status & (BMIC_DATA_READY | BMIC_CHAN_CLEAR)) == 0) break;
-
- if (status & BMIC_DATA_READY) { /* data ready */
- int job_status;
-
- if (IDA_READ_LBELL_I(ida) & JOB_ABORTED) {
- printf("ida%d: idaintr: status:%x local channel should be busy! ",
- cntlr, status);
- }
-
- paddr = IDA_GET_COM_ADDR(ida);
- offset = IDA_GET_COM_OFFSET(ida);
- cstat = IDA_GET_COM_STATUS(ida);
-
- /* acknowledge interrupt */
- IDA_ACK_CMD_COM(ida);
-
- /* determine which job completed */
- qcbp = ida_qcb_phys_kv(ida, paddr);
-
- /* analyse the job status code */
- if (cstat & IDA_COMPL_OK) {
- job_status = JOB_SUCCESS;
- } else {
- printf("ida%d: idaintr: return code %x=", cntlr, cstat);
- if (cstat & IDA_NON_FATAL) printf("recoverable error! ");
- if (cstat & IDA_FATAL) printf("fatal error! ");
- if (cstat & IDA_ABORTED) printf("aborted! ");
- if (cstat & IDA_INVAL_REQ) printf("invalid request block! ");
- if (cstat & IDA_INVAL_LIST) printf("cmd list error! ");
- if (cstat & IDA_AARGH_LIST) printf("really bad cmd list! ");
- job_status = JOB_FAILURE;
- }
-
-#ifdef IDADEBUG
- if (ida_debug & IDA_SHOWQCBS) {
- printf("ida%d: idaintr: qcb(%x) returned.\n", cntlr, qcbp);
- ida_print_qcb(qcbp);
- }
-#endif
-
- ida_done(cntlr, qcbp, job_status); /* retire the job */
- ida_start(cntlr); /* send the controller another job */
- }
-
- if (status & BMIC_CHAN_CLEAR) {
- /* channel not clear */
- IDA_DISABLE_CHAN(ida);
- ida_start(cntlr); /* send the controller another job */
- }
- } /*eisa*/
- }
-}
-
-
-int
-ida_poll(cntlr, wait)
-int cntlr;
-int wait; /* delay in milliseconds */
-{
- struct ida_ctl *ctlp = idadata[cntlr];
-
- if (PCI_CONTROLLER(ctlp)) {
- printf("ida%d: error: ida_poll called on a PCI controller\n", cntlr);
- return EIO;
- }
-
- while (wait-- > 0) {
- if (IDA_DATA_READY(ctlp)) {
- ctlp->com_addr = IDA_GET_COM_ADDR(ctlp);
- ctlp->com_offset = IDA_GET_COM_OFFSET(ctlp);
- ctlp->com_status = IDA_GET_COM_STATUS(ctlp);
- IDA_ACK_CMD_COM(ctlp);
-
- if (0) printf("ida_poll: addr=0x%08x off=0x%04x cmdstatus=0x%02x\n",
- (u_int)ctlp->com_addr,
- ctlp->com_offset,
- ctlp->com_status);
-
- return 0;
- }
- DELAY(1000);
- }
-
- printf("ida%d: board not responding\n", cntlr);
- return EIO;
-}
-
-
-int
-ida_submit(int cntlr, qcb_t *qcbp, int size)
-{
- struct ida_ctl *ida = idadata[cntlr];
- int s = splbio();
-
- if (PCI_CONTROLLER(ida)) {
- ida_pci_reg_t *reg = (ida_pci_reg_t *)ida->iobase;
- u_int fifo = reg->initiate_fifo;
- if (fifo == 1) {
- splx(s);
-#ifdef IDADEBUG
- if (ida_debug & IDA_SHOWSUBS)
- printf("ida%d: ida_submit(%x): fifo=1 not submitting\n",
- cntlr, qcbp, fifo);
-#endif
- return(1); /* not sent - must try again later */
- }
-#ifdef IDADEBUG
- if (ida_debug & IDA_SHOWSUBS)
- printf("ida%d: ida_submit(%x): fifo=%d submitting\n", cntlr, qcbp, fifo);
-#endif
- reg->initiate_fifo = qcbp->paddr;
-
- } else {
- if (!IDA_CHAN_CLEAR(ida)) {
- IDA_ENABLE_CHAN(ida);
- splx(s);
- return(1); /* not sent - must try again later */
- }
-
- IDA_SET_EBELL_I(ida, 2);
- IDA_SET_SUB_ADDR(ida, qcbp->paddr); /* physical address of this qcb */
- IDA_SET_SUB_LEN(ida, size);
- IDA_SET_LBELL_I(ida, 1);
- }
-
- splx(s);
- return(0); /* sent */
-}
-
-static
-void
-ida_empty_pci_complete_fifo(int cntlr, ida_pci_reg_t *reg) {
- u_long paddr;
- if (paddr = reg->complete_fifo) {
- int count = 200;
- while (paddr && count > 0) {
- printf("ida%d: command completion discarded (0x%x).\n",
- cntlr, (u_int)paddr);
- if (paddr = reg->complete_fifo) {
- DELAY(100);
- count--;
- }
- }
- }
- return;
-}
-
-static
-u_long
-ida_complete_pci_command(int cntlr, ida_pci_reg_t *reg) {
- int count = 1;
- u_long paddr;
- while (count < 1000000) {
- if (reg->status & IDA_PCI_PENDING) {
- if ((paddr = reg->complete_fifo) == 0)
- printf("ida%d: ida_complete_pci_command: zero address returned.\n",
- cntlr);
- else
- return paddr;
- }
- DELAY(10);
- }
- return 1;
-}
-
-static
-int
-ida_submit_wait(int cntlr, qcb_t *qcbp, int size)
-{
- struct ida_ctl *ida = idadata[cntlr];
-
- if (PCI_CONTROLLER(ida)) {
- ida_pci_reg_t *reg = (ida_pci_reg_t *)ida->iobase;
- int i, count = 1000000;
- u_long paddr;
- ida_empty_pci_complete_fifo(cntlr, reg);
- reg->interrupt = IDA_PCI_DISABLE_INTS;
- while (count > 0 && (i = reg->initiate_fifo) > 16) {
- DELAY(10);
- count--;
- }
- if (count == 0) {
- printf("ida%d: ida_pci_submit_wait: fifo failed to clear - controller has failed.\n", cntlr);
- return 1;
- }
- reg->initiate_fifo = qcbp->paddr;
- paddr = ida_complete_pci_command(cntlr, reg);
- if (paddr == 1) {
- printf("ida%d: ida_pci_submit_wait timeout. No command list returned.\n",
- cntlr);
- return 1;
- }
- if (paddr != qcbp->paddr) {
- printf("ida%d: ida_pci_submit_wait error. Invalid command list returned.\n",
- cntlr);
- return 1;
- }
- if (qcbp->req.error != 0xfe && qcbp->req.error == 0x40) {
- printf("ida%d: ida_pci_submit_wait: Job error.\n", cntlr);
- return 1;
- }
- } else {
- if (ida_submit(cntlr, qcbp, size)) {
- return 1;
- }
- if (ida_poll(cntlr, 10)) {
- return 1;
- }
- }
-
- return 0; /* sent */
-}
-
-
-void
-ida_done(int cntlr, qcb_t *qcbp, int state)
-{
- struct buf *bp = qcbp->buf;
-
- if (idadata[cntlr] > 0)
- idadata[cntlr]->inside--; /* one less job inside the controller */
-
- if (state != JOB_SUCCESS) {
-#ifdef IDADEBUG
- if (ida_debug & IDA_SHOWMISC)
- printf("ida%d: ida_done: job failed 0x%x\n", cntlr, state);
-#endif
- /* we had a problem */
- bp->b_error = EIO;
- bp->b_flags |= B_ERROR;
- } else {
- struct ida_drv *drv = id_drive[dkunit(bp->b_dev)];
- bp->b_resid = 0;
- /* Update device stats */
- devstat_end_transaction(&drv->dk_stats,
- bp->b_bcount - bp->b_resid,
- DEVSTAT_TAG_NONE,
- (bp->b_flags & B_READ) ? DEVSTAT_READ : DEVSTAT_WRITE);
- }
-
- ida_free_qcb(cntlr, qcbp);
- biodone(bp);
-}
-
-
-int
-idsize(dev_t dev)
-{
- int unit = dkunit(dev);
- struct ida_drv *drv;
-
- if (unit >= NID)
- return (-1);
-
- drv = id_drive[unit];
- if (!drv || !(drv->flags & ID_INIT))
- return (-1);
-
- return (dssize(dev, &drv->slices, idopen, idclose));
-}
-
-/*
- * dump all of physical memory into the partition specified, starting
- * at offset 'dumplo' into the partition.
- */
-int
-iddump(dev_t dev)
-{ /* dump core after a system crash */
- return 0; /* XXX */
-}
-
-static id_devsw_installed = 0;
-
-static void
-id_drvinit(void *unused)
-{
- if( ! id_devsw_installed ) {
- cdevsw_add(&id_cdevsw);
- id_devsw_installed = 1;
- }
-}
-
-SYSINIT(iddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+ID_CDMAJ,id_drvinit,NULL)
-
-#ifdef IDADEBUG
-void
-ida_print_qcb(qcb_t *qcbp)
-{
- int i;
- printf("qcb(%x): drive=%x priority=%x flags=%x sgcount=%d\n"
- ,qcbp
- ,qcbp->hdr.drive
- ,qcbp->hdr.priority
- ,qcbp->hdr.flags
- ,qcbp->req.sgcount);
- printf("qcb(%x): next=%x command=%x error=%x blkno=%x bcount=%x\n"
- ,qcbp
- ,qcbp->req.next
- ,qcbp->req.command
- ,qcbp->req.error
- ,qcbp->req.blkno
- ,qcbp->req.bcount);
- for (i=0; i < qcbp->req.sgcount; i++)
- printf("qcb(%x): %x len=%x addr=%x\n"
- ,qcbp
- ,i
- ,qcbp->sglist[i].len
- ,qcbp->sglist[i].addr);
-}
-
-void
-ida_print_active_qcb(int cntlr)
-{
- struct ida_ctl *ida = idadata[cntlr];
- int i;
-
- for (i=0; i < QCB_HASH_SIZE; i++) {
- qcb_t *qcbp = ida->hashlist[i];
- while (qcbp) {
- if (qcbp->flags != QCB_FREE) {
- ida_print_qcb(qcbp);
- }
- qcbp = qcbp->nexthash;
- }
- }
-}
-#endif /*IDADEBUG */
-
OpenPOWER on IntegriCloud