|
|
GNU Mach 1.0
/*
* 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 [email protected]
* 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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.