diff options
Diffstat (limited to 'scsi/mapped_scsi.c')
-rw-r--r-- | scsi/mapped_scsi.c | 586 |
1 files changed, 586 insertions, 0 deletions
diff --git a/scsi/mapped_scsi.c b/scsi/mapped_scsi.c new file mode 100644 index 0000000..fe3dd77 --- /dev/null +++ b/scsi/mapped_scsi.c @@ -0,0 +1,586 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: mapped_scsi.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 9/90 + * + * In-kernel side of the user-mapped SCSI driver. + */ + +#include <asc.h> +#include <sii.h> +#define NRZ (NASC+NSII) +#if NRZ > 0 +#include <platforms.h> + +#include <machine/machspl.h> /* spl definitions */ + +#include <device/device_types.h> +#include <device/io_req.h> +#include <chips/busses.h> + +#include <vm/vm_kern.h> +#include <kern/eventcount.h> + +#include <scsi/mapped_scsi.h> + +#include <machine/machspl.h> + +#ifdef DECSTATION + +#define machine_btop mips_btop + +#define kvctophys(v) K0SEG_TO_PHYS((v)) /* kernel virtual cached */ +#define phystokvc(p) PHYS_TO_K0SEG((p)) /* and back */ +#define kvutophys(v) K1SEG_TO_PHYS((v)) /* kernel virtual uncached */ +#define phystokvu(p) PHYS_TO_K1SEG((p)) /* and back */ + +#include <mips/mips_cpu.h> +#include <mips/PMAX/kn01.h> +#include <mips/PMAX/pmaz_aa.h> + +#define SII_REG_PHYS(self) kvutophys(self->registers.any) +#define SII_RAM_PHYS(self) (SII_REG_PHYS((self))+(KN01_SYS_SII_B_START-KN01_SYS_SII)) +#define SII_RAM_SIZE (KN01_SYS_SII_B_END-KN01_SYS_SII_B_START) + +#define ASC_REG_PHYS(self) kvutophys(self->registers.any) +#define ASC_DMAR_PHYS(self) (ASC_REG_PHYS((self))+ ASC_OFFSET_DMAR) +#define ASC_RAM_PHYS(self) (ASC_REG_PHYS((self))+ ASC_OFFSET_RAM) + +#define PAD_7061(n) short n +#define PAD_53C94(n) char n[3] + +#endif /*DECSTATION*/ + +#ifdef VAXSTATION +#define machine_btop vax_btop +#endif /*VAXSTATION*/ + +#ifdef P40 + +#define machine_btop mips_btop + +#define kvctophys(v) K0SEG_TO_PHYS((v)) /* kernel virtual cached */ +#define phystokvc(p) PHYS_TO_K0SEG((p)) /* and back */ +#define kvutophys(v) K1SEG_TO_PHYS((v)) /* kernel virtual uncached */ +#define phystokvu(p) PHYS_TO_K1SEG((p)) /* and back */ + +#include <mips/mips_cpu.h> + +#define ASC_RAM_SIZE 0 +#define ASC_OFFSET_DMAR 0 +#define ASC_OFFSET_RAM 0 + +#define ASC_REG_PHYS(self) kvutophys(self->registers.any) +#define ASC_DMAR_PHYS(self) (ASC_REG_PHYS((self))+ ASC_OFFSET_DMAR) +#define ASC_RAM_PHYS(self) (ASC_REG_PHYS((self))+ ASC_OFFSET_RAM) +#endif /* P40 */ + +/* + * Phys defines for the various supported HBAs + */ + +/* DEC7061 */ +#include <scsi/adapters/scsi_7061.h> + +#ifdef PAD_7061 + +typedef struct { + volatile unsigned short sii_sdb; /* rw: Data bus and parity */ + PAD_7061(pad0); + volatile unsigned short sii_sc1; /* rw: scsi signals 1 */ + PAD_7061(pad1); + volatile unsigned short sii_sc2; /* rw: scsi signals 2 */ + PAD_7061(pad2); + volatile unsigned short sii_csr; /* rw: control and status */ + PAD_7061(pad3); + volatile unsigned short sii_id; /* rw: scsi bus ID */ + PAD_7061(pad4); + volatile unsigned short sii_sel_csr; /* rw: selection status */ + PAD_7061(pad5); + volatile unsigned short sii_destat; /* ro: selection detector status */ + PAD_7061(pad6); + volatile unsigned short sii_dstmo; /* unsupp: dssi timeout */ + PAD_7061(pad7); + volatile unsigned short sii_data; /* rw: data register */ + PAD_7061(pad8); + volatile unsigned short sii_dma_ctrl; /* rw: dma control reg */ + PAD_7061(pad9); + volatile unsigned short sii_dma_len; /* rw: length of transfer */ + PAD_7061(pad10); + volatile unsigned short sii_dma_adr_low;/* rw: low address */ + PAD_7061(pad11); + volatile unsigned short sii_dma_adr_hi; /* rw: high address */ + PAD_7061(pad12); + volatile unsigned short sii_dma_1st_byte;/* rw: initial byte */ + PAD_7061(pad13); + volatile unsigned short sii_stlp; /* unsupp: dssi short trgt list ptr */ + PAD_7061(pad14); + volatile unsigned short sii_ltlp; /* unsupp: dssi long " " " */ + PAD_7061(pad15); + volatile unsigned short sii_ilp; /* unsupp: dssi initiator list ptr */ + PAD_7061(pad16); + volatile unsigned short sii_dssi_csr; /* unsupp: dssi control */ + PAD_7061(pad17); + volatile unsigned short sii_conn_csr; /* rc: connection interrupt control */ + PAD_7061(pad18); + volatile unsigned short sii_data_csr; /* rc: data interrupt control */ + PAD_7061(pad19); + volatile unsigned short sii_cmd; /* rw: command register */ + PAD_7061(pad20); + volatile unsigned short sii_diag_csr; /* rw: disgnostic status */ + PAD_7061(pad21); +} sii_padded_regmap_t; + +#else /*!PAD_7061*/ + +typedef sii_regmap_t sii_padded_regmap_t; + +#endif /*!PAD_7061*/ + +/* NCR 53C94 */ +#include <scsi/adapters/scsi_53C94.h> + +#ifdef PAD_53C94 +typedef struct { + volatile unsigned char asc_tc_lsb; /* rw: Transfer Counter LSB */ + PAD_53C94(pad0); + volatile unsigned char asc_tc_msb; /* rw: Transfer Counter MSB */ + PAD_53C94(pad1); + volatile unsigned char asc_fifo; /* rw: FIFO top */ + PAD_53C94(pad2); + volatile unsigned char asc_cmd; /* rw: Command */ + PAD_53C94(pad3); + volatile unsigned char asc_csr; /* r: Status */ +/*#define asc_dbus_id asc_csr /* w: Destination Bus ID */ + PAD_53C94(pad4); + volatile unsigned char asc_intr; /* r: Interrupt */ +/*#define asc_sel_timo asc_intr /* w: (re)select timeout */ + PAD_53C94(pad5); + volatile unsigned char asc_ss; /* r: Sequence Step */ +/*#define asc_syn_p asc_ss /* w: synchronous period */ + PAD_53C94(pad6); + volatile unsigned char asc_flags; /* r: FIFO flags + seq step */ +/*#define asc_syn_o asc_flags /* w: synchronous offset */ + PAD_53C94(pad7); + volatile unsigned char asc_cnfg1; /* rw: Configuration 1 */ + PAD_53C94(pad8); + volatile unsigned char asc_ccf; /* w: Clock Conv. Factor */ + PAD_53C94(pad9); + volatile unsigned char asc_test; /* w: Test Mode */ + PAD_53C94(pad10); + volatile unsigned char asc_cnfg2; /* rw: Configuration 2 */ + PAD_53C94(pad11); + volatile unsigned char asc_cnfg3; /* rw: Configuration 3 */ + PAD_53C94(pad12); + volatile unsigned char asc_rfb; /* w: Reserve FIFO byte */ + PAD_53C94(pad13); +} asc_padded_regmap_t; + +#else /* !PAD_53C94 */ + +typedef asc_regmap_t asc_padded_regmap_t; + +#endif /* !PAD_53C94 */ + +/* + * Co-existency with in-kernel drivers + */ +boolean_t rz_use_mapped_interface = FALSE; + +/* + * Status information for all HBAs + */ +/*static*/ struct RZ_status { + union { + unsigned long any; + asc_padded_regmap_t *asc; + sii_padded_regmap_t *sii; + } registers; + int (*stop)(); + vm_offset_t (*mmap)(); + mapped_scsi_info_t info; + struct evc eventcounter; +} RZ_statii[NRZ]; + +typedef struct RZ_status *RZ_status_t; + + +/* + * Probe routine for all HBAs + */ +RZ_probe(regbase, ui, hba) + unsigned long regbase; + register struct bus_device *ui; +{ + int unit = ui->unit; + vm_offset_t addr; + mapped_scsi_info_t info; + struct RZ_status *self; + + printf("[mappable] "); + + self = &RZ_statii[unit]; + + self->registers.any = regbase; + + /* + * Grab a page to be mapped later to users + */ + (void) kmem_alloc_wired(kernel_map, &addr, PAGE_SIZE); /* kseg2 */ + bzero(addr, PAGE_SIZE); + addr = pmap_extract(pmap_kernel(), addr); /* phys */ + info = (mapped_scsi_info_t) (phystokvc(addr)); + self->info = info; + + /* + * Set permanent info + */ + info->interrupt_count = 0; +/*XXX*/ info->ram_size = ASC_RAM_SIZE; + info->hba_type = hba; + + evc_init(&self->eventcounter); + info->wait_event = self->eventcounter.ev_id; + + return 1; +} + +/* + * Device open procedure + */ +RZ_open(dev, flag, ior) + io_req_t ior; +{ + int unit = dev; + register RZ_status_t self = &RZ_statii[unit]; + + + if (unit >= NRZ) + return D_NO_SUCH_DEVICE; + + /* + * Silence interface, just in case + */ + (*self->stop)(unit); + + /* + * Reset eventcounter + */ + evc_signal(&self->eventcounter); + + rz_use_mapped_interface = TRUE; + + /* + * Do not turn interrupts on. The user can do it when ready + * to take them. + */ + + return 0; +} + +/* + * Device close procedure + */ +RZ_close(dev, flag) +{ + int unit = dev; + register RZ_status_t self = &RZ_statii[unit]; + + if (unit >= NRZ) + return D_NO_SUCH_DEVICE; + + /* + * Silence interface, in case user forgot + */ + (*self->stop)(unit); + + evc_signal(&self->eventcounter); + + rz_use_mapped_interface = FALSE; + + /* XXX rz_kernel_mode(); XXX */ + + return 0; +} + + +/* + * Get status procedure. + * We need to tell that we are mappable. + */ +io_return_t +RZ_get_status(dev, flavor, status, status_count) + int dev; + int flavor; + dev_status_t status; + unsigned int status_count; +{ + return (D_SUCCESS); +} + +/* + * Should not refuse this either + */ +RZ_set_status(dev, flavor, status, status_count) + int dev; + int flavor; + dev_status_t status; + unsigned int status_count; +{ + return (D_SUCCESS); +} + +/* + * Port death notification routine + */ +RZ_portdeath(dev, dead_port) +{ +} + +/* + * Page mapping, switch off to HBA-specific for regs&ram + */ +vm_offset_t +RZ_mmap(dev, off, prot) + int dev; +{ + int unit = dev; + register RZ_status_t self = &RZ_statii[unit]; + vm_offset_t page; + vm_offset_t addr; + io_return_t ret; + + if (off < SCSI_INFO_SIZE) { + addr = kvctophys (self->info) + off; + ret = D_SUCCESS; + } else + ret = (*self->mmap)(self, off, prot, &addr); + + if (ret != D_SUCCESS) + return ret; + + page = machine_btop(addr); + + return (page); +} + + +/* + *--------------------------------------------------------------- + * The rest of the file contains HBA-specific routines + *--------------------------------------------------------------- + */ + +#if NASC > 0 +/* + * Routines for the NCR 53C94 + */ +static +ASC_stop(unit) +{ + register RZ_status_t self = &RZ_statii[unit]; + register asc_padded_regmap_t *regs = self->registers.asc; + int ack; + + ack = regs->asc_intr; /* Just acknowledge pending interrupts */ +} + +ASC_probe(reg, ui) + unsigned long reg; + register struct bus_device *ui; +{ + register RZ_status_t self = &RZ_statii[ui->unit]; + static vm_offset_t ASC_mmap(); + + self->stop = ASC_stop; + self->mmap = ASC_mmap; + return RZ_probe(reg, ui, HBA_NCR_53c94); +} + + +ASC_intr(unit,spllevel) + spl_t spllevel; +{ + register RZ_status_t self = &RZ_statii[unit]; + register asc_padded_regmap_t *regs = self->registers.asc; + register csr, intr, seq_step, cmd; + + /* + * Acknowledge interrupt request + * + * This clobbers some two other registers, therefore + * we read them beforehand. It also clears the intr + * request bit, silencing the interface for now. + */ + csr = regs->asc_csr; + + /* drop spurious interrupts */ + if ((csr & ASC_CSR_INT) == 0) + return; + seq_step = regs->asc_ss; + cmd = regs->asc_cmd; + + intr = regs->asc_intr; /* ack */ + + splx(spllevel); /* drop priority */ + + if (self->info) { + self->info->interrupt_count++; /* total interrupts */ + self->info->saved_regs.asc.csr = csr; + self->info->saved_regs.asc.isr = intr; + self->info->saved_regs.asc.seq = seq_step; + self->info->saved_regs.asc.cmd = cmd; + } + + /* Awake user thread */ + evc_signal(&self->eventcounter); +} + +/* + * Virtual->physical mapping routine for PMAZ-AA + */ +static vm_offset_t +ASC_mmap(self, off, prot, addr) + RZ_status_t self; + vm_offset_t off; + vm_prot_t prot; + vm_offset_t *addr; +{ + /* + * The offset (into the VM object) defines the following layout + * + * off size what + * 0 1pg mapping information (csr & #interrupts) + * 1pg 1pg ASC registers + * 2pg 1pg ASC dma + * 3pg 128k ASC ram buffers + */ + +#define ASC_END (ASC_RAM_BASE+ASC_RAM_SIZE) + + if (off < ASC_DMAR_BASE) + *addr = (vm_offset_t) ASC_REG_PHYS(self) + (off - SCSI_INFO_SIZE); + else if (off < ASC_RAM_BASE) + *addr = (vm_offset_t) ASC_DMAR_PHYS(self) + (off - ASC_REGS_BASE); + else if (off < ASC_END) + *addr = (vm_offset_t) ASC_RAM_PHYS(self) + (off - ASC_RAM_BASE); + else + return D_INVALID_SIZE; + + return D_SUCCESS; +} +#endif NASC > 0 + +#if NSII > 0 +SII_stop(unit) +{ + register RZ_status_t self = &RZ_statii[unit]; + register sii_padded_regmap_t *regs = self->registers.sii; + + regs->sii_csr &= ~SII_CSR_IE; /* disable interrupts */ + /* clear all wtc bits */ + regs->sii_conn_csr = regs->sii_conn_csr; + regs->sii_data_csr = regs->sii_data_csr; +} + +SII_probe(reg, ui) + unsigned long reg; + register struct bus_device *ui; +{ + register RZ_status_t self = &RZ_statii[ui->unit]; + static vm_offset_t SII_mmap(); + + self->stop = SII_stop; + self->mmap = SII_mmap; + return RZ_probe(reg, ui, HBA_DEC_7061); +} + +SII_intr(unit,spllevel) + spl_t spllevel; +{ + register RZ_status_t self = &RZ_statii[unit]; + register sii_padded_regmap_t *regs = self->registers.sii; + register unsigned short conn, data; + + /* + * Disable interrupts, saving cause(s) first. + */ + conn = regs->sii_conn_csr; + data = regs->sii_data_csr; + + /* drop spurious calls */ + if (((conn|data) & (SII_DTR_DI|SII_DTR_CI)) == 0) + return; + + regs->sii_csr &= ~SII_CSR_IE; + + regs->sii_conn_csr = conn; + regs->sii_data_csr = data; + + splx(spllevel); + + if (self->info) { + self->info->interrupt_count++; /* total interrupts */ + self->info->saved_regs.sii.sii_conn_csr = conn; + self->info->saved_regs.sii.sii_data_csr = data; + } + + /* Awake user thread */ + evc_signal(&self->eventcounter); +} + +static vm_offset_t +SII_mmap(self, off, prot, addr) + RZ_status_t self; + vm_offset_t off; + vm_prot_t prot; + vm_offset_t *addr; +{ + /* + * The offset (into the VM object) defines the following layout + * + * off size what + * 0 1pg mapping information (csr & #interrupts) + * 1pg 1pg SII registers + * 2pg 128k SII ram buffer + */ + +#define SII_END (SII_RAM_BASE+SII_RAM_SIZE) + + if (off < SII_RAM_BASE) + *addr = (vm_offset_t) SII_REG_PHYS(self) + (off - SCSI_INFO_SIZE); + else if (off < SII_END) + *addr = (vm_offset_t) SII_RAM_PHYS(self) + (off - SII_RAM_BASE); + else + return D_INVALID_SIZE; + + return D_SUCCESS; +} +#endif NSII > 0 + +#endif NRZ > 0 |