diff options
Diffstat (limited to 'scsi/adapters/scsi_33C93_hdw.c')
-rw-r--r-- | scsi/adapters/scsi_33C93_hdw.c | 2078 |
1 files changed, 0 insertions, 2078 deletions
diff --git a/scsi/adapters/scsi_33C93_hdw.c b/scsi/adapters/scsi_33C93_hdw.c deleted file mode 100644 index 169ccbf9..00000000 --- a/scsi/adapters/scsi_33C93_hdw.c +++ /dev/null @@ -1,2078 +0,0 @@ -/* - * Mach Operating System - * Copyright (c) 1991,1990,1989 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: scsi_33C93_hdw.h - * Author: Alessandro Forin, Carnegie Mellon University - * Date: 8/91 - * - * Bottom layer of the SCSI driver: chip-dependent functions - * - * This file contains the code that is specific to the WD/AMD 33C93 - * SCSI chip (Host Bus Adapter in SCSI parlance): probing, start - * operation, and interrupt routine. - */ - -#if 0 -DISCLAIMER: THIS DOES NOT EVEN COMPILE YET, it went in by mistake. -Code that probably makes some sense is from here to "TILL HERE" - -/* - * This layer works based on small simple 'scripts' that are installed - * at the start of the command and drive the chip to completion. - * The idea comes from the specs of the NCR 53C700 'script' processor. - * - * There are various reasons for this, mainly - * - Performance: identify the common (successful) path, and follow it; - * at interrupt time no code is needed to find the current status - * - Code size: it should be easy to compact common operations - * - Adaptability: the code skeleton should adapt to different chips without - * terrible complications. - * - Error handling: and it is easy to modify the actions performed - * by the scripts to cope with strange but well identified sequences - * - */ - -#include <sbic.h> -#if NSBIC > 0 -#include <platforms.h> - -#ifdef IRIS -#define PAD(n) char n[3] /* or whatever */ -#define SBIC_MUX_ADDRESSING /* comment out if wrong */ -#define SBIC_CLOCK_FREQUENCY 20 /* FIXME FIXME FIXME */ -#define SBIC_MACHINE_DMA_MODE SBIC_CTL_DMA /* FIXME FIXME FIXME */ - -#define SBIC_SET_RST_ADDR /*SCSI_INIT_ADDR*/ -#define SBIC_CLR_RST_ADDR /*SCSI_RDY_ADDR*/ -#define SBIC_MACHINE_RESET_SCSIBUS(regs,per) \ - { int temp; \ - temp = *(volatile unsigned int *)SBIC_SET_RST_ADDR; \ - delay(per); \ - temp = *(volatile unsigned int *)SBIC_CLR_RST_ADDR; \ - } - -#endif - -#include <machine/machspl.h> /* spl definitions */ -#include <mach/std_types.h> -#include <sys/types.h> -#include <chips/busses.h> -#include <scsi/compat_30.h> - -#include <scsi/scsi.h> -#include <scsi/scsi2.h> - -#include <scsi/adapters/scsi_33C93.h> -#include <scsi/scsi_defs.h> -#include <scsi/adapters/scsi_dma.h> - -/* - * Spell out all combinations of padded/nopadded and mux/nomux - */ -#ifdef PAD -typedef struct { - - volatile unsigned char sbic_myid; /* rw: My SCSI id */ -/*#define sbic_cdbsize sbic_myid /* w : size of CDB */ - PAD(pad0) - volatile unsigned char sbic_control; /* rw: Control register */ - PAD(pad1) - volatile unsigned char sbic_timeo; /* rw: Timeout period */ - PAD(pad2) - volatile unsigned char sbic_cdb1; /* rw: CDB, 1st byte */ - PAD(pad3) - volatile unsigned char sbic_cdb2; /* rw: CDB, 2nd byte */ - PAD(pad4) - volatile unsigned char sbic_cdb3; /* rw: CDB, 3rd byte */ - PAD(pad5) - volatile unsigned char sbic_cdb4; /* rw: CDB, 4th byte */ - PAD(pad6) - volatile unsigned char sbic_cdb5; /* rw: CDB, 5th byte */ - PAD(pad7) - volatile unsigned char sbic_cdb6; /* rw: CDB, 6th byte */ - PAD(pad8) - volatile unsigned char sbic_cdb7; /* rw: CDB, 7th byte */ - PAD(pad9) - volatile unsigned char sbic_cdb8; /* rw: CDB, 8th byte */ - PAD(pad10) - volatile unsigned char sbic_cdb9; /* rw: CDB, 9th byte */ - PAD(pad11) - volatile unsigned char sbic_cdb10; /* rw: CDB, 10th byte */ - PAD(pad12) - volatile unsigned char sbic_cdb11; /* rw: CDB, 11th byte */ - PAD(pad13) - volatile unsigned char sbic_cdb12; /* rw: CDB, 12th byte */ - PAD(pad14) - volatile unsigned char sbic_tlun; /* rw: Target LUN */ - PAD(pad15) - volatile unsigned char sbic_cmd_phase; /* rw: Command phase */ - PAD(pad16) - volatile unsigned char sbic_syn; /* rw: Synch xfer params */ - PAD(pad17) - volatile unsigned char sbic_count_hi; /* rw: Xfer count, hi */ - PAD(pad18) - volatile unsigned char sbic_count_med; /* rw: Xfer count, med */ - PAD(pad19) - volatile unsigned char sbic_count_lo; /* rw: Xfer count, lo */ - PAD(pad20) - volatile unsigned char sbic_selid; /* rw: Target ID (select) */ - PAD(pad21) - volatile unsigned char sbic_rselid; /* rw: Target ID (reselect) */ - PAD(pad22) - volatile unsigned char sbic_csr; /* r : Status register */ - PAD(pad23) - volatile unsigned char sbic_cmd; /* rw: Command register */ - PAD(pad24) - volatile unsigned char sbic_data; /* rw: FIFO top */ - PAD(pad25) - char u0; /* unused, padding */ - PAD(pad26) - char u1; /* unused, padding */ - PAD(pad27) - char u2; /* unused, padding */ - PAD(pad28) - char u3; /* unused, padding */ - PAD(pad29) - char u4; /* unused, padding */ - PAD(pad30) - volatile unsigned char sbic_asr; /* r : Aux Status Register */ - PAD(pad31) - -} sbic_padded_mux_regmap_t; - -typedef struct { - volatile unsigned char sbic_asr; /* r : Aux Status Register */ -/*#define sbic_address sbic_asr /* w : desired register no */ - PAD(pad0); - volatile unsigned char sbic_value; /* rw: register value */ - PAD(pad1); -} sbic_padded_ind_regmap_t; - -#else /* !PAD */ - -typedef sbic_mux_regmap_t sbic_padded_mux_regmap_t; -typedef sbic_ind_regmap_t sbic_padded_ind_regmap_t; - -#endif /* !PAD */ - -/* - * Could have used some non-ANSIsm in the following :-)) - */ -#ifdef SBIC_MUX_ADDRESSING - -typedef sbic_padded_mux_regmap_t sbic_padded_regmap_t; - -#define SET_SBIC_myid(regs,val) (regs)->sbic_myid = (val) -#define GET_SBIC_myid(regs,val) (val) = (regs)->sbic_myid -#define SET_SBIC_cdbsize(regs,val) (regs)->sbic_cdbsize = (val) -#define GET_SBIC_cdbsize(regs,val) (val) = (regs)->sbic_cdbsize -#define SET_SBIC_control(regs,val) (regs)->sbic_control = (val) -#define GET_SBIC_control(regs,val) (val) = (regs)->sbic_control -#define SET_SBIC_timeo(regs,val) (regs)->sbic_timeo = (val) -#define GET_SBIC_timeo(regs,val) (val) = (regs)->sbic_timeo -#define SET_SBIC_cdb1(regs,val) (regs)->sbic_cdb1 = (val) -#define GET_SBIC_cdb1(regs,val) (val) = (regs)->sbic_cdb1 -#define SET_SBIC_cdb2(regs,val) (regs)->sbic_cdb2 = (val) -#define GET_SBIC_cdb2(regs,val) (val) = (regs)->sbic_cdb2 -#define SET_SBIC_cdb3(regs,val) (regs)->sbic_cdb3 = (val) -#define GET_SBIC_cdb3(regs,val) (val) = (regs)->sbic_cdb3 -#define SET_SBIC_cdb4(regs,val) (regs)->sbic_cdb4 = (val) -#define GET_SBIC_cdb4(regs,val) (val) = (regs)->sbic_cdb4 -#define SET_SBIC_cdb5(regs,val) (regs)->sbic_cdb5 = (val) -#define GET_SBIC_cdb5(regs,val) (val) = (regs)->sbic_cdb5 -#define SET_SBIC_cdb6(regs,val) (regs)->sbic_cdb6 = (val) -#define GET_SBIC_cdb6(regs,val) (val) = (regs)->sbic_cdb6 -#define SET_SBIC_cdb7(regs,val) (regs)->sbic_cdb7 = (val) -#define GET_SBIC_cdb7(regs,val) (val) = (regs)->sbic_cdb7 -#define SET_SBIC_cdb8(regs,val) (regs)->sbic_cdb8 = (val) -#define GET_SBIC_cdb8(regs,val) (val) = (regs)->sbic_cdb8 -#define SET_SBIC_cdb9(regs,val) (regs)->sbic_cdb9 = (val) -#define GET_SBIC_cdb9(regs,val) (val) = (regs)->sbic_cdb9 -#define SET_SBIC_cdb10(regs,val) (regs)->sbic_cdb10 = (val) -#define GET_SBIC_cdb10(regs,val) (val) = (regs)->sbic_cdb10 -#define SET_SBIC_cdb11(regs,val) (regs)->sbic_cdb11 = (val) -#define GET_SBIC_cdb11(regs,val) (val) = (regs)->sbic_cdb11 -#define SET_SBIC_cdb12(regs,val) (regs)->sbic_cdb12 = (val) -#define GET_SBIC_cdb12(regs,val) (val) = (regs)->sbic_cdb12 -#define SET_SBIC_tlun(regs,val) (regs)->sbic_tlun = (val) -#define GET_SBIC_tlun(regs,val) (val) = (regs)->sbic_tlun -#define SET_SBIC_cmd_phase(regs,val) (regs)->sbic_cmd_phase = (val) -#define GET_SBIC_cmd_phase(regs,val) (val) = (regs)->sbic_cmd_phase -#define SET_SBIC_syn(regs,val) (regs)->sbic_syn = (val) -#define GET_SBIC_syn(regs,val) (val) = (regs)->sbic_syn -#define SET_SBIC_count_hi(regs,val) (regs)->sbic_count_hi = (val) -#define GET_SBIC_count_hi(regs,val) (val) = (regs)->sbic_count_hi -#define SET_SBIC_count_med(regs,val) (regs)->sbic_count_med = (val) -#define GET_SBIC_count_med(regs,val) (val) = (regs)->sbic_count_med -#define SET_SBIC_count_lo(regs,val) (regs)->sbic_count_lo = (val) -#define GET_SBIC_count_lo(regs,val) (val) = (regs)->sbic_count_lo -#define SET_SBIC_selid(regs,val) (regs)->sbic_selid = (val) -#define GET_SBIC_selid(regs,val) (val) = (regs)->sbic_selid -#define SET_SBIC_rselid(regs,val) (regs)->sbic_rselid = (val) -#define GET_SBIC_rselid(regs,val) (val) = (regs)->sbic_rselid -#define SET_SBIC_csr(regs,val) (regs)->sbic_csr = (val) -#define GET_SBIC_csr(regs,val) (val) = (regs)->sbic_csr -#define SET_SBIC_cmd(regs,val) (regs)->sbic_cmd = (val) -#define GET_SBIC_cmd(regs,val) (val) = (regs)->sbic_cmd -#define SET_SBIC_data(regs,val) (regs)->sbic_data = (val) -#define GET_SBIC_data(regs,val) (val) = (regs)->sbic_data - -#define SBIC_TC_SET(regs,val) { \ - (regs)->sbic_count_hi = ((val)>>16)); \ - (regs)->sbic_count_med = (val)>>8; \ - (regs)->sbic_count_lo = (val); \ - } -#define SBIC_TC_GET(regs,val) { \ - (val) = ((regs)->sbic_count_hi << 16) | \ - ((regs)->sbic_count_med << 8) | \ - ((regs)->sbic_count_lo); \ - } - -#define SBIC_LOAD_COMMAND(regs,cmd,cmdsize) { \ - register char *ptr = (char*)(cmd); \ - (regs)->cis_cdb1 = *ptr++; \ - (regs)->cis_cdb2 = *ptr++; \ - (regs)->cis_cdb3 = *ptr++; \ - (regs)->cis_cdb4 = *ptr++; \ - (regs)->cis_cdb5 = *ptr++; \ - (regs)->cis_cdb6 = *ptr++; \ - if (cmdsize > 6) { \ - (regs)->cis_cdb7 = *ptr++; \ - (regs)->cis_cdb8 = *ptr++; \ - (regs)->cis_cdb9 = *ptr++; \ - (regs)->cis_cdb10 = *ptr++; \ - } \ - if (cmdsize > 10) { \ - (regs)->cis_cdb11 = *ptr++; \ - (regs)->cis_cdb12 = *ptr; \ - } \ - } - -#else /*SBIC_MUX_ADDRESSING*/ - -typedef sbic_padded_ind_regmap_t sbic_padded_regmap_t; - -#define SET_SBIC_myid(regs,val) sbic_write_reg(regs,SBIC_myid,val) -#define GET_SBIC_myid(regs,val) sbic_read_reg(regs,SBIC_myid,val) -#define SET_SBIC_cdbsize(regs,val) sbic_write_reg(regs,SBIC_cdbsize,val) -#define GET_SBIC_cdbsize(regs,val) sbic_read_reg(regs,SBIC_cdbsize,val) -#define SET_SBIC_control(regs,val) sbic_write_reg(regs,SBIC_control,val) -#define GET_SBIC_control(regs,val) sbic_read_reg(regs,SBIC_control,val) -#define SET_SBIC_timeo(regs,val) sbic_write_reg(regs,SBIC_timeo,val) -#define GET_SBIC_timeo(regs,val) sbic_read_reg(regs,SBIC_timeo,val) -#define SET_SBIC_cdb1(regs,val) sbic_write_reg(regs,SBIC_cdb1,val) -#define GET_SBIC_cdb1(regs,val) sbic_read_reg(regs,SBIC_cdb1,val) -#define SET_SBIC_cdb2(regs,val) sbic_write_reg(regs,SBIC_cdb2,val) -#define GET_SBIC_cdb2(regs,val) sbic_read_reg(regs,SBIC_cdb2,val) -#define SET_SBIC_cdb3(regs,val) sbic_write_reg(regs,SBIC_cdb3,val) -#define GET_SBIC_cdb3(regs,val) sbic_read_reg(regs,SBIC_cdb3,val) -#define SET_SBIC_cdb4(regs,val) sbic_write_reg(regs,SBIC_cdb4,val) -#define GET_SBIC_cdb4(regs,val) sbic_read_reg(regs,SBIC_cdb4,val) -#define SET_SBIC_cdb5(regs,val) sbic_write_reg(regs,SBIC_cdb5,val) -#define GET_SBIC_cdb5(regs,val) sbic_read_reg(regs,SBIC_cdb5,val) -#define SET_SBIC_cdb6(regs,val) sbic_write_reg(regs,SBIC_cdb6,val) -#define GET_SBIC_cdb6(regs,val) sbic_read_reg(regs,SBIC_cdb6,val) -#define SET_SBIC_cdb7(regs,val) sbic_write_reg(regs,SBIC_cdb7,val) -#define GET_SBIC_cdb7(regs,val) sbic_read_reg(regs,SBIC_cdb7,val) -#define SET_SBIC_cdb8(regs,val) sbic_write_reg(regs,SBIC_cdb8,val) -#define GET_SBIC_cdb8(regs,val) sbic_read_reg(regs,SBIC_cdb8,val) -#define SET_SBIC_cdb9(regs,val) sbic_write_reg(regs,SBIC_cdb9,val) -#define GET_SBIC_cdb9(regs,val) sbic_read_reg(regs,SBIC_cdb9,val) -#define SET_SBIC_cdb10(regs,val) sbic_write_reg(regs,SBIC_cdb10,val) -#define GET_SBIC_cdb10(regs,val) sbic_read_reg(regs,SBIC_cdb10,val) -#define SET_SBIC_cdb11(regs,val) sbic_write_reg(regs,SBIC_cdb11,val) -#define GET_SBIC_cdb11(regs,val) sbic_read_reg(regs,SBIC_cdb11,val) -#define SET_SBIC_cdb12(regs,val) sbic_write_reg(regs,SBIC_cdb12,val) -#define GET_SBIC_cdb12(regs,val) sbic_read_reg(regs,SBIC_cdb12,val) -#define SET_SBIC_tlun(regs,val) sbic_write_reg(regs,SBIC_tlun,val) -#define GET_SBIC_tlun(regs,val) sbic_read_reg(regs,SBIC_tlun,val) -#define SET_SBIC_cmd_phase(regs,val) sbic_write_reg(regs,SBIC_cmd_phase,val) -#define GET_SBIC_cmd_phase(regs,val) sbic_read_reg(regs,SBIC_cmd_phase,val) -#define SET_SBIC_syn(regs,val) sbic_write_reg(regs,SBIC_syn,val) -#define GET_SBIC_syn(regs,val) sbic_read_reg(regs,SBIC_syn,val) -#define SET_SBIC_count_hi(regs,val) sbic_write_reg(regs,SBIC_count_hi,val) -#define GET_SBIC_count_hi(regs,val) sbic_read_reg(regs,SBIC_count_hi,val) -#define SET_SBIC_count_med(regs,val) sbic_write_reg(regs,SBIC_count_med,val) -#define GET_SBIC_count_med(regs,val) sbic_read_reg(regs,SBIC_count_med,val) -#define SET_SBIC_count_lo(regs,val) sbic_write_reg(regs,SBIC_count_lo,val) -#define GET_SBIC_count_lo(regs,val) sbic_read_reg(regs,SBIC_count_lo,val) -#define SET_SBIC_selid(regs,val) sbic_write_reg(regs,SBIC_selid,val) -#define GET_SBIC_selid(regs,val) sbic_read_reg(regs,SBIC_selid,val) -#define SET_SBIC_rselid(regs,val) sbic_write_reg(regs,SBIC_rselid,val) -#define GET_SBIC_rselid(regs,val) sbic_read_reg(regs,SBIC_rselid,val) -#define SET_SBIC_csr(regs,val) sbic_write_reg(regs,SBIC_csr,val) -#define GET_SBIC_csr(regs,val) sbic_read_reg(regs,SBIC_csr,val) -#define SET_SBIC_cmd(regs,val) sbic_write_reg(regs,SBIC_cmd,val) -#define GET_SBIC_cmd(regs,val) sbic_read_reg(regs,SBIC_cmd,val) -#define SET_SBIC_data(regs,val) sbic_write_reg(regs,SBIC_data,val) -#define GET_SBIC_data(regs,val) sbic_read_reg(regs,SBIC_data,val) - -#define SBIC_TC_SET(regs,val) { \ - sbic_write_reg(regs,SBIC_count_hi,((val)>>16)); \ - (regs)->sbic_value = (val)>>8; wbflush(); \ - (regs)->sbic_value = (val); \ - } -#define SBIC_TC_GET(regs,val) { \ - sbic_read_reg(regs,SBIC_count_hi,(val)); \ - (val) = ((val)<<8) | (regs)->sbic_value; \ - (val) = ((val)<<8) | (regs)->sbic_value; \ - } - -#define SBIC_LOAD_COMMAND(regs,cmd,cmdsize) { - register int n=cmdsize-1; \ - register char *ptr = (char*)(cmd); \ - sbic_write_reg(regs,SBIC_cdb1,*ptr++); \ - while (n-- > 0) (regs)->sbic_value = *ptr++; \ - } - -#endif /*SBIC_MUX_ADDRESSING*/ - -#define GET_SBIC_asr(regs,val) (val) = (regs)->sbic_asr - - -/* - * If all goes well (cross fingers) the typical read/write operation - * should complete in just one interrupt. Therefore our scripts - * have only two parts: a pre-condition and an action. The first - * triggers error handling if not satisfied and in our case it is a match - * of .... - * The action part is just a function pointer, invoked in a standard way. - * The script proceeds only if the action routine returns TRUE. - * See sbic_intr() for how and where this is all done. - */ - -typedef struct script { - struct { /* expected state at interrupt: */ - unsigned char csr; /* interrupt cause */ - unsigned char pha; /* command phase */ - } condition; -/* unsigned char unused[2]; /* unused padding */ - boolean_t (*action)(); /* extra operations */ -} *script_t; - -/* Matching on the condition value */ -#define ANY 0xff -#define SCRIPT_MATCH(csr,pha,cond) \ - (((cond).csr == (csr)) && \ - (((cond).pha == (pha)) || ((cond).pha==ANY))) - - -/* forward decls of script actions */ -boolean_t - sbic_end(), /* all come to an end */ - sbic_get_status(), /* get status from target */ - sbic_dma_in(), /* get data from target via dma */ - sbic_dma_in_r(), /* get data from target via dma (restartable)*/ - sbic_dma_out(), /* send data to target via dma */ - sbic_dma_out_r(), /* send data to target via dma (restartable) */ - sbic_dosynch(), /* negotiate synch xfer */ - sbic_msg_in(), /* receive the disconenct message */ - sbic_disconnected(), /* target has disconnected */ - sbic_reconnect(); /* target reconnected */ - -/* forward decls of error handlers */ -boolean_t - sbic_err_generic(), /* generic handler */ - sbic_err_disconn(), /* target disconnects amidst */ - gimmeabreak(); /* drop into the debugger */ - -int sbic_reset_scsibus(); -boolean_t sbic_probe_target(); -static sbic_wait(); - -/* - * State descriptor for this layer. There is one such structure - * per (enabled) SCSI-33c93 interface - */ -struct sbic_softc { - watchdog_t wd; - sbic_padded_regmap_t *regs; /* 33c93 registers */ - - scsi_dma_ops_t *dma_ops; /* DMA operations and state */ - opaque_t dma_state; - - script_t script; /* what should happen next */ - boolean_t (*error_handler)();/* what if something is wrong */ - int in_count; /* amnt we expect to receive */ - int out_count; /* amnt we are going to ship */ - - volatile char state; -#define SBIC_STATE_BUSY 0x01 /* selecting or currently connected */ -#define SBIC_STATE_TARGET 0x04 /* currently selected as target */ -#define SBIC_STATE_COLLISION 0x08 /* lost selection attempt */ -#define SBIC_STATE_DMA_IN 0x10 /* tgt --> initiator xfer */ -#define SBIC_STATE_AM_MODE 0x20 /* 33c93A with advanced mode (AM) */ - - unsigned char ntargets; /* how many alive on this scsibus */ - unsigned char done; - unsigned char unused; - - scsi_softc_t *sc; /* HBA-indep info */ - target_info_t *active_target; /* the current one */ - - target_info_t *next_target; /* trying to seize bus */ - queue_head_t waiting_targets;/* other targets competing for bus */ - -} sbic_softc_data[NSBIC]; - -typedef struct sbic_softc *sbic_softc_t; - -sbic_softc_t sbic_softc[NSBIC]; - -/* - * Synch xfer parameters, and timing conversions - */ -int sbic_min_period = SBIC_SYN_MIN_PERIOD; /* in cycles = f(ICLK,FSn) */ -int sbic_max_offset = SBIC_SYN_MAX_OFFSET; /* pure number */ - -int sbic_to_scsi_period(regs,a) -{ - unsigned int fs; - - /* cycle = DIV / (2*CLK) */ - /* DIV = FS+2 */ - /* best we can do is 200ns at 20Mhz, 2 cycles */ - - GET_SBIC_myid(regs,fs); - fs = (fs >>6) + 2; /* DIV */ - fs = (fs * 1000) / (SBIC_CLOCK_FREQUENCY<<1); /* Cycle, in ns */ - if (a < 2) a = 8; /* map to Cycles */ - return ((fs*a)>>2); /* in 4 ns units */ -} - -int scsi_period_to_sbic(regs,p) -{ - register unsigned int fs; - - /* Just the inverse of the above */ - - GET_SBIC_myid(regs,fs); - fs = (fs >>6) + 2; /* DIV */ - fs = (fs * 1000) / (SBIC_CLOCK_FREQUENCY<<1); /* Cycle, in ns */ - - ret = p << 2; /* in ns units */ - ret = ret / fs; /* in Cycles */ - if (ret < sbic_min_period) - return sbic_min_period; - /* verify rounding */ - if (sbic_to_scsi_period(regs,ret) < p) - ret++; - return (ret >= 8) ? 0 : ret; -} - -#define u_min(a,b) (((a) < (b)) ? (a) : (b)) - -/* - * Definition of the controller for the auto-configuration program. - */ - -int sbic_probe(), scsi_slave(), scsi_attach(), sbic_go(), sbic_intr(); - -caddr_t sbic_std[NSBIC] = { 0 }; -struct bus_device *sbic_dinfo[NSBIC*8]; -struct bus_ctlr *sbic_minfo[NSBIC]; -struct bus_driver sbic_driver = - { sbic_probe, scsi_slave, scsi_attach, sbic_go, sbic_std, "rz", sbic_dinfo, - "sbic", sbic_minfo, BUS_INTR_B4_PROBE}; - - -sbic_set_dmaops(unit, dmaops) - unsigned int unit; - scsi_dma_ops_t *dmaops; -{ - if (unit < NSBIC) - sbic_std[unit] = (caddr_t)dmaops; -} - -/* - * Scripts - */ -struct script -sbic_script_any_cmd[] = { /* started with SEL & XFER */ - {{SBIC_CSR_S_XFERRED, 0x60}, sbic_get_status}, -}, - -sbic_script_try_synch[] = { /* started with SEL */ - {{SBIC_CSR_INITIATOR, ANY}, sbic_dosynch}, - {{SBIC_CSR_S_XFERRED, 0x60}, sbic_get_status}, -}; - - -#define DEBUG -#ifdef DEBUG - -#define PRINT(x) if (scsi_debug) printf x - -sbic_state(regs, overrule) - sbic_padded_regmap_t *regs; -{ - register unsigned char asr,tmp; - - if (regs == 0) { - if (sbic_softc[0]) - regs = sbic_softc[0]->regs; - else - regs = (sbic_padded_regmap_t*)0xXXXXXXXX; - } - - GET_SBIC_asr(regs,asr); - - if ((asr & SBIC_ASR_BSY) && !overrule) - db_printf("-BUSY- "); - else { - unsigned char tlun,pha,selid,rselid; - unsigned int cnt; - GET_SBIC_tlun(regs,tlun); - GET_SBIC_cmd_phase(regs,pha); - GET_SBIC_selid(regs,selid); - GET_SBIC_rselid(regs,rselid); - SBIC_TC_GET(regs,cnt); - db_printf("tc %x tlun %x sel %x rsel %x pha %x ", - cnt, tlun, selid, rselid, pha); - } - - if (asr & SBIC_ASR_INT) - db_printf("-INT- "); - else { - GET_SBIC_csr(regs,tmp); - db_printf("csr %x ", tmp); - } - - if (asr & SBIC_ASR_CIP) - db_printf("-CIP-\n"); - else { - GET_SBIC_cmd(regs,tmp); - db_printf("cmd %x\n", tmp); - } - return 0; -} - -sbic_target_state(tgt) - target_info_t *tgt; -{ - if (tgt == 0) - tgt = sbic_softc[0]->active_target; - if (tgt == 0) - return 0; - db_printf("@x%x: fl %x dma %X+%x cmd %x@%X id %x per %x off %x ior %X ret %X\n", - tgt, - tgt->flags, tgt->dma_ptr, tgt->transient_state.dma_offset, tgt->cur_cmd, - tgt->cmd_ptr, tgt->target_id, tgt->sync_period, tgt->sync_offset, - tgt->ior, tgt->done); - if (tgt->flags & TGT_DISCONNECTED){ - script_t spt; - - spt = tgt->transient_state.script; - db_printf("disconnected at "); - db_printsym(spt,1); - db_printf(": %x %x ", spt->condition.csr, spt->condition.pha); - db_printsym(spt->action,1); - db_printf(", "); - db_printsym(tgt->transient_state.handler, 1); - db_printf("\n"); - } - - return 0; -} - -sbic_all_targets(unit) -{ - int i; - target_info_t *tgt; - for (i = 0; i < 8; i++) { - tgt = sbic_softc[unit]->sc->target[i]; - if (tgt) - sbic_target_state(tgt); - } -} - -sbic_script_state(unit) -{ - script_t spt = sbic_softc[unit]->script; - - if (spt == 0) return 0; - db_printsym(spt,1); - db_printf(": %x %x ", spt->condition.csr, spt->condition.pha); - db_printsym(spt->action,1); - db_printf(", "); - db_printsym(sbic_softc[unit]->error_handler, 1); - return 0; -} - -#define TRMAX 200 -int tr[TRMAX+3]; -int trpt, trpthi; -#define TR(x) tr[trpt++] = x -#define TRWRAP trpthi = trpt; trpt = 0; -#define TRCHECK if (trpt > TRMAX) {TRWRAP} - -#define TRACE - -#ifdef TRACE - -#define LOGSIZE 256 -int sbic_logpt; -char sbic_log[LOGSIZE]; - -#define MAXLOG_VALUE 0x1e -struct { - char *name; - unsigned int count; -} logtbl[MAXLOG_VALUE]; - -static LOG(e,f) - char *f; -{ - sbic_log[sbic_logpt++] = (e); - if (sbic_logpt == LOGSIZE) sbic_logpt = 0; - if ((e) < MAXLOG_VALUE) { - logtbl[(e)].name = (f); - logtbl[(e)].count++; - } -} - -sbic_print_log(skip) - int skip; -{ - register int i, j; - register unsigned char c; - - for (i = 0, j = sbic_logpt; i < LOGSIZE; i++) { - c = sbic_log[j]; - if (++j == LOGSIZE) j = 0; - if (skip-- > 0) - continue; - if (c < MAXLOG_VALUE) - db_printf(" %s", logtbl[c].name); - else - db_printf("-x%x", c & 0x7f); - } -} - -sbic_print_stat() -{ - register int i; - register char *p; - for (i = 0; i < MAXLOG_VALUE; i++) { - if (p = logtbl[i].name) - printf("%d %s\n", logtbl[i].count, p); - } -} - -#else /*TRACE*/ -#define LOG(e,f) -#define LOGSIZE -#endif /*TRACE*/ - -#else /*DEBUG*/ -#define PRINT(x) -#define LOG(e,f) -#define LOGSIZE - -#endif /*DEBUG*/ - - -/* - * Probe/Slave/Attach functions - */ - -/* - * Probe routine: - * Should find out (a) if the controller is - * present and (b) which/where slaves are present. - * - * Implementation: - * Send a test-unit-ready to each possible target on the bus - * except of course ourselves. - */ -sbic_probe(reg, ui) - unsigned reg; - struct bus_ctlr *ui; -{ - int unit = ui->unit; - sbic_softc_t sbic = &sbic_softc_data[unit]; - int target_id; - scsi_softc_t *sc; - register sbic_padded_regmap_t *regs; - spl_t s; - boolean_t did_banner = FALSE; - - /* - * We are only called if the right board is there, - * but make sure anyways.. - */ - if (check_memory(reg, 0)) - return 0; - -#if MAPPABLE - /* Mappable version side */ - SBIC_probe(reg, ui); -#endif /*MAPPABLE*/ - - /* - * Initialize hw descriptor, cache some pointers - */ - sbic_softc[unit] = sbic; - sbic->regs = (sbic_padded_regmap_t *) (reg); - - if ((sbic->dma_ops = (scsi_dma_ops_t *)sbic_std[unit]) == 0) - /* use same as unit 0 if undefined */ - sbic->dma_ops = (scsi_dma_ops_t *)sbic_std[0]; - - sbic->dma_state = (*sbic->dma_ops->init)(unit, reg); - - queue_init(&sbic->waiting_targets); - - sc = scsi_master_alloc(unit, sbic); - sbic->sc = sc; - - sc->go = sbic_go; - sc->watchdog = scsi_watchdog; - sc->probe = sbic_probe_target; - sbic->wd.reset = sbic_reset_scsibus; - -#ifdef MACH_KERNEL - sc->max_dma_data = -1; -#else - sc->max_dma_data = scsi_per_target_virtual; -#endif - - regs = sbic->regs; - - /* - * Reset chip, fully. Note that interrupts are already enabled. - */ - s = splbio(); - if (sbic_reset(regs, TRUE)) - sbic->state |= SBIC_STATE_AM_MODE; - - /* - * Our SCSI id on the bus. - * The user can probably set this via the prom. - * If not, it is easy to fix: make a default that - * can be changed as boot arg. Otherwise we keep - * what the prom used. - */ -#ifdef unneeded - SET_SBIC_myid(regs, (scsi_initiator_id[unit] & 0x7)); - sbic_reset(regs, TRUE); -#endif - GET_SBIC_myid(regs,sc->initiator_id); - sc->initiator_id &= 0x7; - printf("%s%d: SCSI id %d", ui->name, unit, sc->initiator_id); - - /* - * For all possible targets, see if there is one and allocate - * a descriptor for it if it is there. - */ - for (target_id = 0; target_id < 8; target_id++) { - register unsigned char asr, csr, pha; - register scsi_status_byte_t status; - - /* except of course ourselves */ - if (target_id == sc->initiator_id) - continue; - - SBIC_TC_SET(regs,0); - SET_SBIC_selid(regs,target_id); - SET_SBIC_timo(regs,SBIC_TIMEOUT(250,SBIC_CLOCK_FREQUENCY)); - - /* - * See if the unit is ready. - * XXX SHOULD inquiry LUN 0 instead !!! - */ - { - scsi_command_test_unit_ready_y c; - bzero(&c, sizeof(c)); - c.scsi_cmd_code = SCSI_CMD_TEST_UNIT_READY; - SBIC_LOAD_COMMAND(regs,&c,sizeof(c)); - } - - /* select and send it */ - SET_SBIC_cmd(regs,SBIC_CMD_SEL_XFER); - - /* wait for the chip to complete, or timeout */ - asr = sbic_wait(regs, SBIC_ASR_INT); - GET_SBIC_csr(regs,csr); - - /* - * Check if the select timed out - */ - GET_SBIC_cmd_phase(regs,pha); - if ((SBIC_CPH(pha) == 0) && (csr & SBIC_CSR_CMD_ERR)) { - /* noone out there */ -#if notsure - SET_SBIC_cmd(regs,SBIC_CMD_DISC); - asr = sbic_wait(regs, SBIC_ASR_INT); - GET_SBIC_csr(regs,csr); -#endif - continue; - } - - printf(",%s%d", did_banner++ ? " " : " target(s) at ", - target_id); - - if (SBIC_CPH(pha) < 0x60) - /* XXX recover by hand XXX */ - panic(" target acts weirdo"); - - GET_SBIC_tlun(regs,status.bits); - - if (status.st.scsi_status_code != SCSI_ST_GOOD) - scsi_error( 0, SCSI_ERR_STATUS, status.bits, 0); - - /* - * Found a target - */ - sbic->ntargets++; - { - register target_info_t *tgt; - tgt = scsi_slave_alloc(sc->masterno, target_id, sbic); - - (*sbic->dma_ops->new_target)(sbic->dma_state, tgt); - } - } - - printf(".\n"); - - splx(s); - return 1; -} - -boolean_t -sbic_probe_target(tgt, ior) - target_info_t *tgt; - io_req_t ior; -{ - sbic_softc_t sbic = sbic_softc[tgt->masterno]; - boolean_t newlywed; - - newlywed = (tgt->cmd_ptr == 0); - if (newlywed) { - (*sbic->dma_ops->new_target)(sbic->dma_state, tgt); - } - - if (scsi_inquiry(tgt, SCSI_INQ_STD_DATA) == SCSI_RET_DEVICE_DOWN) - return FALSE; - - tgt->flags = TGT_ALIVE; - return TRUE; -} - -static sbic_wait(regs, until) - sbic_padded_regmap_t *regs; - char until; -{ - register unsigned char val; - int timeo = 1000000; - - GET_SBIC_asr(regs,val); - while ((val & until) == 0) { - if (!timeo--) { - printf("sbic_wait TIMEO with x%x\n", regs->sbic_csr); - break; - } - delay(1); - GET_SBIC_asr(regs,val); - } - return val; -} - -boolean_t -sbic_reset(regs, quick) - sbic_padded_regmap_t *regs; -{ - char my_id, csr; - - /* preserve our ID for now */ - GET_SBIC_myid(regs,my_id); - my_id &= SBIC_ID_MASK; - - if (SBIC_CLOCK_FREQUENCY < 11) - my_id |= SBIC_ID_FS_8_10; - else if (SBIC_CLOCK_FREQUENCY < 16) - my_id |= SBIC_ID_FS_12_15; - else if (SBIC_CLOCK_FREQUENCY < 21) - my_id |= SBIC_ID_FS_16_20; - - my_id |= SBIC_ID_EAF|SBIC_ID_EHP; - - SET_SBIC_myid(regs,myid); - wbflush(); - - /* - * Reset chip and wait till done - */ - SET_SBIC_cmd(regs,SBIC_CMD_RESET); - delay(25); - - (void) sbic_wait(regs, SBIC_ASR_INT); - GET_SBIC_csr(regs,csr); /* clears interrupt also */ - - /* - * Set up various chip parameters - */ - SET_SBIC_control(regs, SBIC_CTL_HHP|SBIC_CTL_EDI|SBIC_CTL_HSP| - SBIC_MACHINE_DMA_MODE); - /* will do IDI on the fly */ - SET_SBIC_rselid(regs, SBIC_RID_ER|SBIC_RID_ES|SBIC_RID_DSP); - SET_SBIC_syn(regs,SBIC_SYN(0,sbic_min_period)); /* asynch for now */ - - /* anything else was zeroed by reset */ - - if (quick) - return (csr & SBIC_CSR_RESET_AM); - - /* - * reset the scsi bus, the interrupt routine does the rest - * or you can call sbic_bus_reset(). - */ - /* - * Now HOW do I do this ? I just want to drive the SCSI "RST" - * signal true for about 25 usecs; But the chip has no notion - * of such a signal at all. The spec suggest that the chip's - * reset pin be connected to the RST signal, which makes this - * operation a machdep one. - */ - SBIC_MACHINE_RESET_SCSIBUS(regs, 30); - - return (csr & SBIC_CSR_RESET_AM); -} - -/* - * Operational functions - */ - -/* - * Start a SCSI command on a target - */ -sbic_go(tgt, cmd_count, in_count, cmd_only) - target_info_t *tgt; - boolean_t cmd_only; -{ - sbic_softc_t sbic; - register spl_t s; - boolean_t disconn; - script_t scp; - boolean_t (*handler)(); - - LOG(1,"go"); - - sbic = (sbic_softc_t)tgt->hw_state; - - tgt->transient_state.cmd_count = cmd_count; /* keep it here */ - - (*sbic->dma_ops->map)(sbic->dma_state, tgt); - - disconn = BGET(scsi_might_disconnect,tgt->masterno,tgt->target_id); - disconn = disconn && (sbic->ntargets > 1); - disconn |= BGET(scsi_should_disconnect,tgt->masterno,tgt->target_id); - - /* - * Setup target state - */ - tgt->done = SCSI_RET_IN_PROGRESS; - - handler = (disconn) ? sbic_err_disconn : sbic_err_generic; - scp = sbic_script_any_cmd; - - switch (tgt->cur_cmd) { - case SCSI_CMD_READ: - case SCSI_CMD_LONG_READ: - LOG(2,"readop"); - break; - case SCSI_CMD_WRITE: - case SCSI_CMD_LONG_WRITE: - LOG(0x1a,"writeop"); - break; - case SCSI_CMD_INQUIRY: - /* This is likely the first thing out: - do the synch neg if so */ - if (!cmd_only && ((tgt->flags&TGT_DID_SYNCH)==0)) { - scp = sbic_script_try_synch; - tgt->flags |= TGT_TRY_SYNCH; - break; - } - case SCSI_CMD_MODE_SELECT: - case SCSI_CMD_REASSIGN_BLOCKS: - case SCSI_CMD_FORMAT_UNIT: - tgt->transient_state.cmd_count = sizeof(scsi_command_group_0); - tgt->transient_state.out_count = cmd_count - sizeof(scsi_command_group_0); - /* fall through */ - case SCSI_CMD_REQUEST_SENSE: - case SCSI_CMD_MODE_SENSE: - case SCSI_CMD_RECEIVE_DIAG_RESULTS: - case SCSI_CMD_READ_CAPACITY: - case SCSI_CMD_READ_BLOCK_LIMITS: - case SCSI_CMD_READ_TOC: - case SCSI_CMD_READ_SUBCH: - case SCSI_CMD_READ_HEADER: - LOG(0x1c,"cmdop"); - LOG(0x80+tgt->cur_cmd,0); - break; - case SCSI_CMD_TEST_UNIT_READY: - /* - * Do the synch negotiation here, unless prohibited - * or done already - */ - if ( ! (tgt->flags & TGT_DID_SYNCH)) { - scp = sbic_script_try_synch; - tgt->flags |= TGT_TRY_SYNCH; - cmd_only = FALSE; - } - /* fall through */ - default: - LOG(0x1c,"cmdop"); - LOG(0x80+tgt->cur_cmd,0); - break; - } - - tgt->transient_state.script = scp; - tgt->transient_state.handler = handler; - tgt->transient_state.identify = (cmd_only) ? 0xff : - (disconn ? SCSI_IDENTIFY|SCSI_IFY_ENABLE_DISCONNECT : - SCSI_IDENTIFY); - - if (in_count) - tgt->transient_state.in_count = - (in_count < tgt->block_size) ? tgt->block_size : in_count; - else - tgt->transient_state.in_count = 0; - - /* - * See if another target is currently selected on - * this SCSI bus, e.g. lock the sbic structure. - * Note that it is the strategy routine's job - * to serialize ops on the same target as appropriate. - * XXX here and everywhere, locks! - */ - /* - * Protection viz reconnections makes it tricky. - */ - s = splbio(); - - if (sbic->wd.nactive++ == 0) - sbic->wd.watchdog_state = SCSI_WD_ACTIVE; - - if (sbic->state & SBIC_STATE_BUSY) { - /* - * Queue up this target, note that this takes care - * of proper FIFO scheduling of the scsi-bus. - */ - LOG(3,"enqueue"); - enqueue_tail(&sbic->waiting_targets, (queue_entry_t) tgt); - } else { - /* - * It is down to at most two contenders now, - * we will treat reconnections same as selections - * and let the scsi-bus arbitration process decide. - */ - sbic->state |= SBIC_STATE_BUSY; - sbic->next_target = tgt; - sbic_attempt_selection(sbic); - /* - * Note that we might still lose arbitration.. - */ - } - splx(s); -} - -sbic_attempt_selection(sbic) - sbic_softc_t sbic; -{ - target_info_t *tgt; - sbic_padded_regmap_t *regs; - register unsigned char val; - register int out_count; - - regs = sbic->regs; - tgt = sbic->next_target; - - LOG(4,"select"); - LOG(0x80+tgt->target_id,0); - - /* - * We own the bus now.. unless we lose arbitration - */ - sbic->active_target = tgt; - - /* Try to avoid reselect collisions */ - GET_SBIC_asr(regs,val); - if (val & SBIC_ASR_INT) - return; - - /* - * Init bus state variables - */ - sbic->script = tgt->transient_state.script; - sbic->error_handler = tgt->transient_state.handler; - sbic->done = SCSI_RET_IN_PROGRESS; - - sbic->out_count = 0; - sbic->in_count = 0; - - /* Define how the identify msg should be built */ - GET_SBIC_rselid(regs, val); - val &= ~(SBIC_RID_MASK|SBIC_RID_ER); - /* the enable reselection bit is used to build the identify msg */ - if (tgt->transient_state.identify != 0xff) - val |= (tgt->transient_state.identify & SCSI_IFY_ENABLE_DISCONNECT) << 1; - SET_SBIC_rselid(regs, val); - SET_SBIC_tlun(regs, tgt->lun); - - /* - * Start the chip going - */ - out_count = (*sbic->dma_ops->start_cmd)(sbic->dma_state, tgt); - SBIC_TC_PUT(regs, out_count); - - val = tgt->target_id; - if (tgt->transient_state.in_count) - val |= SBIC_SID_FROM_SCSI; - SET_SBIC_selid(regs, val); - - SET_SBIC_timo(regs,SBIC_TIMEOUT(250,SBIC_CLOCK_FREQUENCY)); - - SET_SBIC_syn(regs,SBIC_SYN(tgt->sync_offset,tgt->sync_period)); - - /* ugly little help for compiler */ -#define command out_count - if (tgt->flags & TGT_DID_SYNCH) { - command = (tgt->transient_state.identify == 0xff) ? - SBIC_CMD_SEL_XFER : - SBIC_CMD_SEL_ATN_XFER; /*preferred*/ - } else if (tgt->flags & TGT_TRY_SYNCH) - command = SBIC_CMD_SEL_ATN; - else - command = SBIC_CMD_SEL_XFER; - - /* load 10 bytes anyways, the chip knows how much to use */ - SBIC_LOAD_COMMAND(regs, tgt->cmd_ptr, 10); - - /* Try to avoid reselect collisions */ - GET_SBIC_asr(regs,val); - if (val & SBIC_ASR_INT) - return; - - SET_SBIC_cmd_phase(regs, 0); /* not a resume */ - SET_SBIC_cmd(regs, command); -#undef command -} - -/* - * Interrupt routine - * Take interrupts from the chip - * - * Implementation: - * Move along the current command's script if - * all is well, invoke error handler if not. - */ -sbic_intr(unit, spllevel) - spl_t spllevel; -{ - register sbic_softc_t sbic; - register script_t scp; - register int asr, csr, pha; - register sbic_padded_regmap_t *regs; -#if MAPPABLE - extern boolean_t rz_use_mapped_interface; - - if (rz_use_mapped_interface) - return SBIC_intr(unit,spllevel); -#endif /*MAPPABLE*/ - - sbic = sbic_softc[unit]; - regs = sbic->regs; - - LOG(5,"\n\tintr"); - - /* drop spurious interrupts */ - GET_SBIC_asr(regs, asr); - if ((asr & SBIC_ASR_INT) == 0) - return; - - /* collect ephemeral information */ - GET_SBIC_cmd_phase(regs, pha); - GET_SBIC_csr(regs, csr); - -TR(csr);TR(asr);TR(pha);TRCHECK - - /* XXX verify this is indeed the case for a SCSI RST asserted */ - if ((csr & SBIC_CSR_CAUSE) == SBIC_CSR_RESET) - return sbic_bus_reset(sbic); - - /* we got an interrupt allright */ - if (sbic->active_target) - sbic->wd.watchdog_state = SCSI_WD_ACTIVE; - - splx(spllevel); /* drop priority */ - - if ((sbic->state & SBIC_STATE_TARGET) || - (csr == SBIC_CSR_RSLT_AM) || (csr == SBIC_CSR_RSLT_NOAM) || - (csr == SBIC_CSR_SLT) || (csr == SBIC_CSR_SLT_ATN)) - return sbic_target_intr(sbic); - - /* - * In attempt_selection() we gave the select command even if - * the chip might have been reconnected already. - */ - if ((csr == SBIC_CSR_RSLT_NI) || (csr == SBIC_CSR_RSLT_IFY)) - return sbic_reconnect(sbic, csr, pha); - - /* - * Check for parity errors - */ - if (asr & SBIC_ASR_PE) { - char *msg; -printf("{PE %x,%x}", asr, pha); - - msg = "SCSI bus parity error"; - /* all we can do is to throw a reset on the bus */ - printf( "sbic%d: %s%s", sbic - sbic_softc_data, msg, - ", attempting recovery.\n"); - sbic_reset(regs, FALSE); - return; - } - - if ((scp = sbic->script) == 0) /* sanity */ - return; - - LOG(6,"match"); - if (SCRIPT_MATCH(csr,pha,scp->condition)) { - /* - * Perform the appropriate operation, - * then proceed - */ - if ((*scp->action)(sbic, csr, pha)) { - sbic->script = scp + 1; - } - } else - return (*sbic->error_handler)(sbic, csr, pha); -} - -sbic_target_intr() -{ - panic("SBIC: TARGET MODE !!!\n"); -} - -/* - * Routines that the interrupt code might switch to - */ - -boolean_t -sbic_end(sbic, csr, pha) - register sbic_softc_t sbic; -{ - register target_info_t *tgt; - register io_req_t ior; - - LOG(8,"end"); - - tgt = sbic->active_target; - if ((tgt->done = sbic->done) == SCSI_RET_IN_PROGRESS) - tgt->done = SCSI_RET_SUCCESS; - - sbic->script = 0; - - if (sbic->wd.nactive-- == 1) - sbic->wd.watchdog_state = SCSI_WD_INACTIVE; - - sbic_release_bus(sbic); - - if (ior = tgt->ior) { - (*sbic->dma_ops->end_cmd)(sbic->dma_state, tgt, ior); - LOG(0xA,"ops->restart"); - (*tgt->dev_ops->restart)( tgt, TRUE); - } - - return FALSE; -} - -boolean_t -sbic_release_bus(sbic) - register sbic_softc_t sbic; -{ - boolean_t ret = TRUE; - - LOG(9,"release"); - if (sbic->state & SBIC_STATE_COLLISION) { - - LOG(0xB,"collided"); - sbic->state &= ~SBIC_STATE_COLLISION; - sbic_attempt_selection(sbic); - - } else if (queue_empty(&sbic->waiting_targets)) { - - sbic->state &= ~SBIC_STATE_BUSY; - sbic->active_target = 0; - sbic->script = 0; - ret = FALSE; - - } else { - - LOG(0xC,"dequeue"); - sbic->next_target = (target_info_t *) - dequeue_head(&sbic->waiting_targets); - sbic_attempt_selection(sbic); - } - return ret; -} - -boolean_t -sbic_get_status(sbic, csr, pha) - register sbic_softc_t sbic; -{ - register sbic_padded_regmap_t *regs = sbic->regs; - register scsi2_status_byte_t status; - int len; - io_req_t ior; - register target_info_t *tgt = sbic->active_target; - - LOG(0xD,"get_status"); -TRWRAP - - sbic->state &= ~SBIC_STATE_DMA_IN; - - /* - * Get the status byte - */ - GET_SBIC_tlun(regs, status.bits); - - if (status.st.scsi_status_code != SCSI_ST_GOOD) { - scsi_error(sbic->active_target, SCSI_ERR_STATUS, status.bits, 0); - sbic->done = (status.st.scsi_status_code == SCSI_ST_BUSY) ? - SCSI_RET_RETRY : SCSI_RET_NEED_SENSE; - } else - sbic->done = SCSI_RET_SUCCESS; - - /* Tell DMA engine we are done */ - (*sbic->dma_ops->end_xfer)(sbic->dma_state, tgt, tgt->transient_state.in_count); - - return sbic_end(sbic, csr, pha); - -} - -#if 0 - -boolean_t -sbic_dma_in(sbic, csr, ir) - register sbic_softc_t sbic; -{ - register target_info_t *tgt; - register sbic_padded_regmap_t *regs = sbic->regs; - register int count; - unsigned char ff = regs->sbic_flags; - - LOG(0xE,"dma_in"); - tgt = sbic->active_target; - - sbic->state |= SBIC_STATE_DMA_IN; - - count = (*sbic->dma_ops->start_datain)(sbic->dma_state, tgt); - SBIC_TC_PUT(regs, count); - - if ((sbic->in_count = count) == tgt->transient_state.in_count) - return TRUE; - regs->sbic_cmd = sbic->script->command; - sbic->script = sbic_script_restart_data_in; - return FALSE; -} - -sbic_dma_in_r(sbic, csr, ir) - register sbic_softc_t sbic; -{ - register target_info_t *tgt; - register sbic_padded_regmap_t *regs = sbic->regs; - register int count; - boolean_t advance_script = TRUE; - - - LOG(0xE,"dma_in"); - tgt = sbic->active_target; - - sbic->state |= SBIC_STATE_DMA_IN; - - if (sbic->in_count == 0) { - /* - * Got nothing yet, we just reconnected. - */ - register int avail; - - /* - * Rather than using the messy RFB bit in cnfg2 - * (which only works for synch xfer anyways) - * we just bump up the dma offset. We might - * endup with one more interrupt at the end, - * so what. - * This is done in sbic_err_disconn(), this - * way dma (of msg bytes too) is always aligned - */ - - count = (*sbic->dma_ops->restart_datain_1) - (sbic->dma_state, tgt); - - /* common case of 8k-or-less read ? */ - advance_script = (tgt->transient_state.in_count == count); - - } else { - - /* - * We received some data. - */ - register int offset, xferred; - - /* - * Problem: sometimes we get a 'spurious' interrupt - * right after a reconnect. It goes like disconnect, - * reconnect, dma_in_r, here but DMA is still rolling. - * Since there is no good reason we got here to begin with - * we just check for the case and dismiss it: we should - * get another interrupt when the TC goes to zero or the - * target disconnects. - */ - SBIC_TC_GET(regs,xferred); - if (xferred != 0) - return FALSE; - - xferred = sbic->in_count - xferred; - assert(xferred > 0); - - tgt->transient_state.in_count -= xferred; - assert(tgt->transient_state.in_count > 0); - - count = (*sbic->dma_ops->restart_datain_2) - (sbic->dma_state, tgt, xferred); - - sbic->in_count = count; - SBIC_TC_PUT(regs, count); - regs->sbic_cmd = sbic->script->command; - - (*sbic->dma_ops->restart_datain_3) - (sbic->dma_state, tgt); - - /* last chunk ? */ - if (count == tgt->transient_state.in_count) - sbic->script++; - - return FALSE; - } - - sbic->in_count = count; - SBIC_TC_PUT(regs, count); - - if (!advance_script) { - regs->sbic_cmd = sbic->script->command; - } - return advance_script; -} - - -/* send data to target. Only called to start the xfer */ - -boolean_t -sbic_dma_out(sbic, csr, ir) - register sbic_softc_t sbic; -{ - register sbic_padded_regmap_t *regs = sbic->regs; - register int reload_count; - register target_info_t *tgt; - int command; - - LOG(0xF,"dma_out"); - - SBIC_TC_GET(regs, reload_count); - sbic->extra_count = regs->sbic_flags & SBIC_FLAGS_FIFO_CNT; - reload_count += sbic->extra_count; - SBIC_TC_PUT(regs, reload_count); - sbic->state &= ~SBIC_STATE_DMA_IN; - - tgt = sbic->active_target; - - command = sbic->script->command; - - if ((sbic->out_count = reload_count) >= - tgt->transient_state.out_count) - sbic->script++; - else - sbic->script = sbic_script_restart_data_out; - - if ((*sbic->dma_ops->start_dataout) - (sbic->dma_state, tgt, ®s->sbic_cmd, command)) { - regs->sbic_cmd = command; - } - - return FALSE; -} - -/* send data to target. Called in two different ways: - (a) to restart a big transfer and - (b) after reconnection - */ -boolean_t -sbic_dma_out_r(sbic, csr, ir) - register sbic_softc_t sbic; -{ - register sbic_padded_regmap_t *regs = sbic->regs; - register target_info_t *tgt; - boolean_t advance_script = TRUE; - int count; - - - LOG(0xF,"dma_out"); - - tgt = sbic->active_target; - sbic->state &= ~SBIC_STATE_DMA_IN; - - if (sbic->out_count == 0) { - /* - * Nothing committed: we just got reconnected - */ - count = (*sbic->dma_ops->restart_dataout_1) - (sbic->dma_state, tgt); - - /* is this the last chunk ? */ - advance_script = (tgt->transient_state.out_count == count); - } else { - /* - * We sent some data. - */ - register int offset, xferred; - - SBIC_TC_GET(regs,count); - - /* see comment above */ - if (count) { - return FALSE; - } - - count += (regs->sbic_flags & SBIC_FLAGS_FIFO_CNT); - count -= sbic->extra_count; - xferred = sbic->out_count - count; - assert(xferred > 0); - - tgt->transient_state.out_count -= xferred; - assert(tgt->transient_state.out_count > 0); - - count = (*sbic->dma_ops->restart_dataout_2) - (sbic->dma_state, tgt, xferred); - - /* last chunk ? */ - if (tgt->transient_state.out_count == count) - goto quickie; - - sbic->out_count = count; - - sbic->extra_count = (*sbic->dma_ops->restart_dataout_3) - (sbic->dma_state, tgt, ®s->sbic_fifo); - SBIC_TC_PUT(regs, count); - regs->sbic_cmd = sbic->script->command; - - (*sbic->dma_ops->restart_dataout_4)(sbic->dma_state, tgt); - - return FALSE; - } - -quickie: - sbic->extra_count = (*sbic->dma_ops->restart_dataout_3) - (sbic->dma_state, tgt, ®s->sbic_fifo); - - sbic->out_count = count; - - SBIC_TC_PUT(regs, count); - - if (!advance_script) { - regs->sbic_cmd = sbic->script->command; - } - return advance_script; -} -#endif /*0*/ - -boolean_t -sbic_dosynch(sbic, csr, pha) - register sbic_softc_t sbic; - register unsigned char csr, pha; -{ - register sbic_padded_regmap_t *regs = sbic->regs; - register unsigned char c; - int i, per, offs; - register target_info_t *tgt; - - /* - * Try synch negotiation - * Phase is MSG_OUT here. - */ - tgt = sbic->active_target; - -#if 0 - regs->sbic_cmd = SBIC_CMD_FLUSH; - delay(2); - - per = sbic_min_period; - if (BGET(scsi_no_synchronous_xfer,sbic->sc->masterno,tgt->target_id)) - offs = 0; - else - offs = sbic_max_offset; - - tgt->flags |= TGT_DID_SYNCH; /* only one chance */ - tgt->flags &= ~TGT_TRY_SYNCH; - - regs->sbic_fifo = SCSI_EXTENDED_MESSAGE; - regs->sbic_fifo = 3; - regs->sbic_fifo = SCSI_SYNC_XFER_REQUEST; - regs->sbic_fifo = sbic_to_scsi_period(regs,sbic_min_period); - regs->sbic_fifo = offs; - regs->sbic_cmd = SBIC_CMD_XFER_INFO; - csr = sbic_wait(regs, SBIC_CSR_INT); - ir = regs->sbic_intr; - - if (SCSI_PHASE(csr) != SCSI_PHASE_MSG_IN) - gimmeabreak(); - - regs->sbic_cmd = SBIC_CMD_XFER_INFO; - csr = sbic_wait(regs, SBIC_CSR_INT); - ir = regs->sbic_intr; - - while ((regs->sbic_flags & SBIC_FLAGS_FIFO_CNT) > 0) - c = regs->sbic_fifo; /* see what it says */ - - if (c == SCSI_MESSAGE_REJECT) { - printf(" did not like SYNCH xfer "); - - /* Tk50s get in trouble with ATN, sigh. */ - regs->sbic_cmd = SBIC_CMD_CLR_ATN; - - goto cmd; - } - - /* - * Receive the rest of the message - */ - regs->sbic_cmd = SBIC_CMD_MSG_ACPT; - sbic_wait(regs, SBIC_CSR_INT); - ir = regs->sbic_intr; - - if (c != SCSI_EXTENDED_MESSAGE) - gimmeabreak(); - - regs->sbic_cmd = SBIC_CMD_XFER_INFO; - sbic_wait(regs, SBIC_CSR_INT); - c = regs->sbic_intr; - if (regs->sbic_fifo != 3) - panic("sbic_dosynch"); - - for (i = 0; i < 3; i++) { - regs->sbic_cmd = SBIC_CMD_MSG_ACPT; - sbic_wait(regs, SBIC_CSR_INT); - c = regs->sbic_intr; - - regs->sbic_cmd = SBIC_CMD_XFER_INFO; - sbic_wait(regs, SBIC_CSR_INT); - c = regs->sbic_intr;/*ack*/ - c = regs->sbic_fifo; - - if (i == 1) tgt->sync_period = scsi_period_to_sbic(regs,c); - if (i == 2) tgt->sync_offset = c; - } - -cmd: - regs->sbic_cmd = SBIC_CMD_MSG_ACPT; - csr = sbic_wait(regs, SBIC_CSR_INT); - c = regs->sbic_intr; - - /* phase should normally be command here */ - if (SCSI_PHASE(csr) == SCSI_PHASE_CMD) { - /* test unit ready or what ? */ - regs->sbic_fifo = 0; - regs->sbic_fifo = 0; - regs->sbic_fifo = 0; - regs->sbic_fifo = 0; - regs->sbic_fifo = 0; - regs->sbic_fifo = 0; - SBIC_TC_PUT(regs,0xff); - regs->sbic_cmd = SBIC_CMD_XFER_PAD; /*0x98*/ - csr = sbic_wait(regs, SBIC_CSR_INT); - ir = regs->sbic_intr;/*ack*/ - } - -status: - if (SCSI_PHASE(csr) != SCSI_PHASE_STATUS) - gimmeabreak(); - -#endif - return TRUE; -} - -/* - * The bus was reset - */ -sbic_bus_reset(sbic) - register sbic_softc_t sbic; -{ - register sbic_padded_regmap_t *regs = sbic->regs; - - LOG(0x1d,"bus_reset"); - - /* - * Clear bus descriptor - */ - sbic->script = 0; - sbic->error_handler = 0; - sbic->active_target = 0; - sbic->next_target = 0; - sbic->state &= SBIC_STATE_AM_MODE; /* save this one bit only */ - queue_init(&sbic->waiting_targets); - sbic->wd.nactive = 0; - (void) sbic_reset(regs, TRUE); - - printf("sbic: (%d) bus reset ", ++sbic->wd.reset_count); - delay(scsi_delay_after_reset); /* some targets take long to reset */ - - if (sbic->sc == 0) /* sanity */ - return; - - scsi_bus_was_reset(sbic->sc); -} - -/* - * Disconnect/reconnect mode ops - */ - -/* save all relevant data, free the BUS */ -boolean_t -sbic_disconnected(sbic, csr, pha) - register sbic_softc_t sbic; - register unsigned char csr, pha; - -{ - register target_info_t *tgt; - - LOG(0x11,"disconnected"); - - tgt = sbic->active_target; - tgt->flags |= TGT_DISCONNECTED; - tgt->transient_state.handler = sbic->error_handler; - /* anything else was saved in sbic_err_disconn() */ - - PRINT(("{D%d}", tgt->target_id)); - - sbic_release_bus(sbic); - - return FALSE; -} - -/* See who reconnected, restore BUS */ -boolean_t -sbic_reconnect(sbic, csr, ir) - register sbic_softc_t sbic; - register unsigned char csr, ir; - -{ - register target_info_t *tgt; - sbic_padded_regmap_t *regs; - int id, pha; - - LOG(0x12,"reconnect"); - /* - * See if this reconnection collided with a selection attempt - */ - if (sbic->state & SBIC_STATE_BUSY) - sbic->state |= SBIC_STATE_COLLISION; - - sbic->state |= SBIC_STATE_BUSY; - - /* find tgt */ - regs = sbic->regs; - GET_SBIC_rselid(regs,id); - - id &= 0x7; - - if ((sbic->state & SBIC_STATE_AM) == 0) { - /* Must pick the identify */ - pha = 0x44; - } else - pha = 0x45; - - tgt = sbic->sc->target[id]; - if (id > 7 || tgt == 0) panic("sbic_reconnect"); - - /* synch things*/ - SET_SBIC_syn(regs,SBIC_SYN(tgt->sync_offset,tgt->sync_period)); - - PRINT(("{R%d}", id)); - if (sbic->state & SBIC_STATE_COLLISION) - PRINT(("[B %d-%d]", sbic->active_target->target_id, id)); - - LOG(0x80+id,0); - - sbic->active_target = tgt; - tgt->flags &= ~TGT_DISCONNECTED; - - sbic->script = tgt->transient_state.script; - sbic->error_handler = tgt->transient_state.handler; - sbic->in_count = 0; - sbic->out_count = 0; - -set counter and setup dma, then - - /* Resume the command now */ - SET_SBIC_cmd_phase(regs, pha); - SET_SBIC_cmd(regs, SBIC_CMD_SEL_XFER); - - return FALSE; -} - -TILL HERE - -/* - * Error handlers - */ - -/* - * Fall-back error handler. - */ -sbic_err_generic(sbic, csr, ir) - register sbic_softc_t sbic; -{ - LOG(0x13,"err_generic"); - - /* handle non-existant or powered off devices here */ - if ((ir == SBIC_INT_DISC) && - (sbic_isa_select(sbic->cmd_was)) && - (SBIC_SS(sbic->ss_was) == 0)) { - /* Powered off ? */ - if (sbic->active_target->flags & TGT_FULLY_PROBED) - sbic->active_target->flags = 0; - sbic->done = SCSI_RET_DEVICE_DOWN; - sbic_end(sbic, csr, ir); - return; - } - - switch (SCSI_PHASE(csr)) { - case SCSI_PHASE_STATUS: - if (sbic->script[-1].condition == SCSI_PHASE_STATUS) { - /* some are just slow to get out.. */ - } else - sbic_err_to_status(sbic, csr, ir); - return; - break; - case SCSI_PHASE_DATAI: - if (sbic->script->condition == SCSI_PHASE_STATUS) { -/* printf("{P}");*/ - return; - } - break; - case SCSI_PHASE_DATAO: - if (sbic->script->condition == SCSI_PHASE_STATUS) { - /* - * See comment above. Actually seen on hitachis. - */ -/* printf("{P}");*/ - return; - } - } - gimmeabreak(); -} - -/* - * Handle disconnections as exceptions - */ -sbic_err_disconn(sbic, csr, ir) - register sbic_softc_t sbic; - register unsigned char csr, ir; -{ - register sbic_padded_regmap_t *regs; - register target_info_t *tgt; - int count; - boolean_t callback = FALSE; - - LOG(0x16,"err_disconn"); - - if (SCSI_PHASE(csr) != SCSI_PHASE_MSG_IN) - return sbic_err_generic(sbic, csr, ir); - - regs = sbic->regs; - tgt = sbic->active_target; - - switch (sbic->script->condition) { - case SCSI_PHASE_DATAO: - LOG(0x1b,"+DATAO"); - if (sbic->out_count) { - register int xferred, offset; - - SBIC_TC_GET(regs,xferred); /* temporary misnomer */ - xferred += regs->sbic_flags & SBIC_FLAGS_FIFO_CNT; - xferred -= sbic->extra_count; - xferred = sbic->out_count - xferred; /* ok now */ - tgt->transient_state.out_count -= xferred; - assert(tgt->transient_state.out_count > 0); - - callback = (*sbic->dma_ops->disconn_1) - (sbic->dma_state, tgt, xferred); - - } else { - - callback = (*sbic->dma_ops->disconn_2) - (sbic->dma_state, tgt); - - } - sbic->extra_count = 0; - tgt->transient_state.script = sbic_script_restart_data_out; - break; - - - case SCSI_PHASE_DATAI: - LOG(0x17,"+DATAI"); - if (sbic->in_count) { - register int offset, xferred; - - SBIC_TC_GET(regs,count); - xferred = sbic->in_count - count; - assert(xferred > 0); - -if (regs->sbic_flags & 0xf) -printf("{Xf %x,%x,%x}", xferred, sbic->in_count, regs->sbic_flags & SBIC_FLAGS_FIFO_CNT); - tgt->transient_state.in_count -= xferred; - assert(tgt->transient_state.in_count > 0); - - callback = (*sbic->dma_ops->disconn_3) - (sbic->dma_state, tgt, xferred); - - tgt->transient_state.script = sbic_script_restart_data_in; - if (tgt->transient_state.in_count == 0) - tgt->transient_state.script++; - - } - tgt->transient_state.script = sbic->script; - break; - - case SCSI_PHASE_STATUS: - /* will have to restart dma */ - SBIC_TC_GET(regs,count); - if (sbic->state & SBIC_STATE_DMA_IN) { - register int offset, xferred; - - LOG(0x1a,"+STATUS+R"); - - xferred = sbic->in_count - count; - assert(xferred > 0); - -if (regs->sbic_flags & 0xf) -printf("{Xf %x,%x,%x}", xferred, sbic->in_count, regs->sbic_flags & SBIC_FLAGS_FIFO_CNT); - tgt->transient_state.in_count -= xferred; -/* assert(tgt->transient_state.in_count > 0);*/ - - callback = (*sbic->dma_ops->disconn_4) - (sbic->dma_state, tgt, xferred); - - tgt->transient_state.script = sbic_script_restart_data_in; - if (tgt->transient_state.in_count == 0) - tgt->transient_state.script++; - - } else { - - /* add what's left in the fifo */ - count += (regs->sbic_flags & SBIC_FLAGS_FIFO_CNT); - /* take back the extra we might have added */ - count -= sbic->extra_count; - /* ..and drop that idea */ - sbic->extra_count = 0; - - LOG(0x19,"+STATUS+W"); - - - if ((count == 0) && (tgt->transient_state.out_count == sbic->out_count)) { - /* all done */ - tgt->transient_state.script = sbic->script; - tgt->transient_state.out_count = 0; - } else { - register int xferred, offset; - - /* how much we xferred */ - xferred = sbic->out_count - count; - - tgt->transient_state.out_count -= xferred; - assert(tgt->transient_state.out_count > 0); - - callback = (*sbic->dma_ops->disconn_5) - (sbic->dma_state,tgt,xferred); - - tgt->transient_state.script = sbic_script_restart_data_out; - } - sbic->out_count = 0; - } - break; - default: - gimmeabreak(); - return; - } - sbic_msg_in(sbic,csr,ir); - sbic->script = sbic_script_disconnect; - regs->sbic_cmd = SBIC_CMD_XFER_INFO|SBIC_CMD_DMA; - if (callback) - (*sbic->dma_ops->disconn_callback)(sbic->dma_state, tgt); -} - -/* - * Watchdog - * - * We know that some (name withdrawn) disks get - * stuck in the middle of dma phases... - */ -sbic_reset_scsibus(sbic) - register sbic_softc_t sbic; -{ - register target_info_t *tgt = sbic->active_target; - register sbic_padded_regmap_t *regs = sbic->regs; - register int ir; - - if (scsi_debug && tgt) { - int dmalen; - SBIC_TC_GET(sbic->regs,dmalen); - printf("Target %d was active, cmd x%x in x%x out x%x Sin x%x Sou x%x dmalen x%x\n", - tgt->target_id, tgt->cur_cmd, - tgt->transient_state.in_count, tgt->transient_state.out_count, - sbic->in_count, sbic->out_count, - dmalen); - } - ir = regs->sbic_intr; - if ((ir & SBIC_INT_RESEL) && (SCSI_PHASE(regs->sbic_csr) == SCSI_PHASE_MSG_IN)) { - /* getting it out of the woods is a bit tricky */ - spl_t s = splbio(); - - (void) sbic_reconnect(sbic, regs->sbic_csr, ir); - sbic_wait(regs, SBIC_CSR_INT); - ir = regs->sbic_intr; - regs->sbic_cmd = SBIC_CMD_MSG_ACPT; - splx(s); - } else { - regs->sbic_cmd = SBIC_CMD_BUS_RESET; - delay(35); - } -} - -#endif NSBIC > 0 - -#endif 0 |