diff options
Diffstat (limited to 'scsi/adapters/scsi_aha17_hdw.c')
-rw-r--r-- | scsi/adapters/scsi_aha17_hdw.c | 1371 |
1 files changed, 0 insertions, 1371 deletions
diff --git a/scsi/adapters/scsi_aha17_hdw.c b/scsi/adapters/scsi_aha17_hdw.c deleted file mode 100644 index d8afe6ab..00000000 --- a/scsi/adapters/scsi_aha17_hdw.c +++ /dev/null @@ -1,1371 +0,0 @@ -/* - * Mach Operating System - * Copyright (c) 1993 Carnegie Mellon University - * Copyright (c) 1993 University of Dublin - * 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 the following 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 AND THE UNIVERSITY OF DUBLIN ALLOW FREE USE OF - * THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON AND THE - * UNIVERSITY OF DUBLIN DISCLAIM 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. - */ -/* - * Support for AHA-174x in enhanced mode. Dominic Herity (dherity@cs.tcd.ie) - * Will refer to "Adaptec AHA-1740A/1742A/1744 Technical Reference Manual" - * page x-y as TRMx-y in comments below. - */ - -#include <eaha.h> -#if NEAHA > 0 - -#define db_printf printf - -#include <cpus.h> -#include <platforms.h> -#include <aha.h> - -#ifdef OSF -#include <eisa.h> -#else -#include <i386at/eisa.h> -#endif - -#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/scsi_defs.h> - -#include <scsi/adapters/scsi_aha15.h> -#include <vm/vm_kern.h> - -#ifdef AT386 -#define MACHINE_PGBYTES I386_PGBYTES -#define MAPPABLE 0 -#define gimmeabreak() asm("int3") - - -#include <i386/pio.h> /* inlining of outb and inb */ -#ifdef OSF -#include <machine/mp/mp.h> -#endif -#endif /*AT386*/ - -#ifdef CBUS -#include <cbus/cbus.h> -#endif - - -#ifndef MACHINE_PGBYTES /* cross compile check */ -#define MACHINE_PGBYTES 0x1000 -#define MAPPABLE 1 -#define gimmeabreak() Debugger("gimmeabreak"); -#endif - -int eaha_probe(), scsi_slave(), eaha_go(), eaha_intr(); -void scsi_attach(); - -vm_offset_t eaha_std[NEAHA] = { 0 }; -struct bus_device *eaha_dinfo[NEAHA*8]; -struct bus_ctlr *eaha_minfo[NEAHA]; -struct bus_driver eaha_driver = - { eaha_probe, scsi_slave, scsi_attach, eaha_go, eaha_std, "rz", - eaha_dinfo, "eahac", eaha_minfo, BUS_INTR_B4_PROBE}; - - -#define TRACE -#ifdef TRACE - -#define LOGSIZE 256 -int eaha_logpt; -char eaha_log[LOGSIZE]; - -#define MAXLOG_VALUE 0x1e -struct { - char *name; - unsigned int count; -} logtbl[MAXLOG_VALUE]; - -static LOG( - int e, - char *f) -{ - eaha_log[eaha_logpt++] = (e); - if (eaha_logpt == LOGSIZE) eaha_logpt = 0; - if ((e) < MAXLOG_VALUE) { - logtbl[(e)].name = (f); - logtbl[(e)].count++; - } -} - -eaha_print_log( - int skip) -{ - register int i, j; - register unsigned char c; - - for (i = 0, j = eaha_logpt; i < LOGSIZE; i++) { - c = eaha_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", c & 0x7f); - } - return 0; -} - -eaha_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*/ - -#ifdef DEBUG -#define ASSERT(x) { if (!(x)) gimmeabreak() ; } -#define MARK() gimmeabreak() -#else -#define ASSERT(x) -#define MARK() -#endif - -/* - * Notes : - * - * do each host command TRM6-4 - * find targets in probe - * disable SCSI writes - * matching port with structs, eaha_go with port, eaha_intr with port - * - */ - -/* eaha registers. See TRM4-11..23. dph */ - -#define HID0(z) ((z)+0xC80) -#define HID1(z) ((z)+0xC81) -#define HID2(z) ((z)+0xC82) -#define HID3(z) ((z)+0xC83) -#define EBCTRL(z) ((z)+0xC84) -#define PORTADDR(z) ((z)+0xCC0) -#define BIOSADDR(z) ((z)+0xCC1) -#define INTDEF(z) ((z)+0xCC2) -#define SCSIDEF(z) ((z)+0xCC3) -#define MBOXOUT0(z) ((z)+0xCD0) -#define MBOXOUT1(z) ((z)+0xCD1) -#define MBOXOUT2(z) ((z)+0xCD2) -#define MBOXOUT3(z) ((z)+0xCD3) -#define MBOXIN0(z) ((z)+0xCD8) -#define MBOXIN1(z) ((z)+0xCD9) -#define MBOXIN2(z) ((z)+0xCDA) -#define MBOXIN3(z) ((z)+0xCDB) -#define ATTN(z) ((z)+0xCD4) -#define G2CNTRL(z) ((z)+0xCD5) -#define G2INTST(z) ((z)+0xCD6) -#define G2STAT(z) ((z)+0xCD7) -#define G2STAT2(z) ((z)+0xCDC) - -/* - * Enhanced mode data structures: ring, enhanced ccbs, a per target buffer - */ - -#define SCSI_TARGETS 8 /* Allow for SCSI-2 */ - - -/* Extended Command Control Block Format. See TRM6-3..12. */ - -typedef struct { - unsigned short command ; -# define EAHA_CMD_NOP 0 -# define EAHA_CMD_INIT_CMD 1 -# define EAHA_CMD_DIAG 5 -# define EAHA_CMD_INIT_SCSI 6 -# define EAHA_CMD_READ_SENS 8 -# define EAHA_CMD_DOWNLOAD 9 -# define EAHA_CMD_HOST_INQ 0x0a -# define EAHA_CMD_TARG_CMD 0x10 - - /* - * It appears to be customary to tackle the endian-ness of - * bit fields as follows, so I won't deviate. However, nothing in - * K&R implies that bit fields are implemented so that the fields - * of an unsigned char are allocated lsb first. Indeed, K&R _warns_ - * _against_ using bit fields to describe storage allocation. - * This issue is separate from endian-ness. dph - * And this is exactly the reason macros are used. If your compiler - * is weird just override the macros and we will all be happy. af - */ - BITFIELD_3(unsigned char, - cne:1, - xxx0:6, - di:1) ; - BITFIELD_7(unsigned char, - xxx1:2, - ses:1, - xxx2:1, - sg:1, - xxx3:1, - dsb:1, - ars:1) ; - - BITFIELD_5(unsigned char, - lun:3, - tag:1, - tt:2, - nd:1, - xxx4:1) ; - BITFIELD_7(unsigned char, - dat:1, - dir:1, - st:1, - chk:1, - xxx5:2, - rec:1, - nbr:1) ; - - unsigned short xxx6 ; - - vm_offset_t scather ; /* scatter/gather */ - unsigned scathlen ; - vm_offset_t status ; - vm_offset_t chain ; - int xxx7 ; - - vm_offset_t sense_p ; - unsigned char sense_len ; - unsigned char cdb_len ; - unsigned short checksum ; - scsi_command_group_5 cdb ; - unsigned char buffer[256] ; /* space for data returned. */ - -} eccb ; - -#define NTARGETS (8) -#define NECCBS (NTARGETS+2) /* Targets + 2 to allow for temporaries. */ - /* Can be up to 64 (TRM6-2), but that entails lots of bss usage */ - -typedef struct { /* Status Block Format. See TRM6-13..19. */ - BITFIELD_8(unsigned char, - don:1, - du:1, - xxx0:1, - qf:1, - sc:1, - dover:1, - ch:1, - inti:1) ; - BITFIELD_8(unsigned char, - asa:1, /* Error in TRM6-15..16 says both asa and sns */ - sns:1, /* bit 9. Bits 8 and 10 are not mentioned. */ - xxx1:1, - ini:1, - me:1, - xxx2:1, - eca:1, - xxx3:1) ; - - unsigned char ha_status ; -# define HA_STATUS_SUCCESS 0x00 -# define HA_STATUS_HOST_ABORTED 0x04 -# define HA_STATUS_ADP_ABORTED 0x05 -# define HA_STATUS_NO_FIRM 0x08 -# define HA_STATUS_NOT_TARGET 0x0a -# define HA_STATUS_SEL_TIMEOUT 0x11 -# define HA_STATUS_OVRUN 0x12 -# define HA_STATUS_BUS_FREE 0x13 -# define HA_STATUS_PHASE_ERROR 0x14 -# define HA_STATUS_BAD_OPCODE 0x16 -# define HA_STATUS_INVALID_LINK 0x17 -# define HA_STATUS_BAD_CBLOCK 0x18 -# define HA_STATUS_DUP_CBLOCK 0x19 -# define HA_STATUS_BAD_SCATHER 0x1a -# define HA_STATUS_RSENSE_FAIL 0x1b -# define HA_STATUS_TAG_REJECT 0x1c -# define HA_STATUS_HARD_ERROR 0x20 -# define HA_STATUS_TARGET_NOATTN 0x21 -# define HA_STATUS_HOST_RESET 0x22 -# define HA_STATUS_OTHER_RESET 0x23 -# define HA_STATUS_PROG_BAD_SUM 0x80 - - scsi2_status_byte_t target_status ; - - unsigned residue ; - vm_offset_t residue_buffer ; - unsigned short add_stat_len ; - unsigned char sense_len ; - char xxx4[9] ; - unsigned char cdb[6] ; - -} status_block ; - -typedef struct { - vm_offset_t ptr ; - unsigned len ; -} scather_entry ; - -#define SCATHER_ENTRIES 128 /* TRM 6-11 */ - -struct erccbx { - target_info_t *active_target; - eccb _eccb; - status_block status ; - struct erccbx *next ; -} ; - -typedef struct erccbx erccb ; - -/* forward decls */ -int eaha_reset_scsibus(); -boolean_t eaha_probe_target(); - -/* - * State descriptor for this layer. There is one such structure - * per (enabled) board - */ -typedef struct { - watchdog_t wd; - decl_simple_lock_data(, aha_lock) - int port; /* I/O port */ - - int has_sense_info [NTARGETS]; - int sense_info_lun [NTARGETS]; - /* 1742 enhanced mode will hang if target has - * sense info and host doesn't request it (TRM6-34). - * This sometimes happens in the scsi driver. - * These flags indicate when a target has sense - * info to disgorge. - * If set, eaha_go reads and discards sense info - * before running any command except request sense. - * dph - */ - - scsi_softc_t *sc; /* HBA-indep info */ - - erccb _erccbs[NECCBS] ; /* mailboxes */ - erccb *toperccb ; - - /* This chicanery is for mapping back the phys address - of a CCB (which we get in an MBI) to its virtual */ - /* [we could use phystokv(), but it isn't standard] */ - vm_offset_t I_hold_my_phys_address; - - char host_inquiry_data[256] ; /* Check out ../scsi2.h */ - -} eaha_softc ; - -eaha_softc eaha_softc_data[NEAHA]; - -typedef eaha_softc *eaha_softc_t; - -eaha_softc_t eaha_softc_pool[NEAHA]; - -int eaha_quiet ; - -erccb *erccb_alloc( - eaha_softc *eaha) -{ - erccb *e ; - int x ; - - do { - while (eaha->toperccb == 0) ;/* Shouldn't be often or long, */ - /* BUT should use a semaphore */ - x = splbio() ; - e = eaha->toperccb ; - if (e == 0) - splx(x) ; - } while (!e) ; - eaha->toperccb = e->next ; - splx(x) ; - bzero(e,sizeof(*e)) ; - e->_eccb.status = kvtophys((vm_offset_t)&e->status) ; - return e ; -} - -void erccb_free( - eaha_softc *eaha, - erccb *e) -{ - int x ; - ASSERT ( e >= eaha->_erccbs && e < eaha->_erccbs+NECCBS) ; - x = splbio() ; - e->next = eaha->toperccb ; - eaha->toperccb = e ; - splx(x) ; -} - -void eaha_mboxout( - int port, - vm_offset_t phys) -{ - outb(MBOXOUT0(port),phys) ; - outb(MBOXOUT1(port),phys>>8) ; - outb(MBOXOUT2(port),phys>>16) ; - outb(MBOXOUT3(port),phys>>24) ; -} - -void eaha_command( /* start a command */ - int port, - erccb *_erccb) -{ - int s ; - vm_offset_t phys = kvtophys((vm_offset_t) &_erccb->_eccb) ; - while ((inb(G2STAT(port)) & 0x04)==0); /*While MBO busy. TRM6-1 */ - s = splbio() ; - eaha_mboxout(port,phys) ; - while (inb(G2STAT(port)) & 1) ; /* While adapter busy. TRM6-2 */ - outb(ATTN(port),0x40 | _erccb->active_target->target_id) ; /* TRM6-20 */ - /* (Should use target id for intitiator command) */ - splx(s) ; -} - -eaha_reset( - eaha_softc_t eaha, - boolean_t quick) -{ - /* - * Reset board and wait till done - */ - unsigned st ; - int target_id ; - int port = eaha->port ; - - /* Reset adapter, maybe with SCSIbus */ - eaha_mboxout(port, quick ? 0x00080080 : 0x00000080 ) ; /* TRM 6-43..45 */ - outb(ATTN(port), 0x10 | inb(SCSIDEF(port)) & 0x0f) ; - outb(G2CNTRL(port),0x20) ; /* TRM 4-22 */ - - do { - st = inb(G2INTST(port)) >> 4 ; - } while (st == 0) ; - /* TRM 4-22 implies that 1 should not be returned in G2INTST, but - in practise, it is. So this code takes 0 to mean non-completion. */ - - for (target_id = 0 ; target_id < NTARGETS; target_id++) - eaha->has_sense_info[target_id] = FALSE ; - -} - -void eaha_init( - eaha_softc_t eaha) -{ - /* Do nothing - I guess */ -} - -void eaha_bus_reset( - eaha_softc_t eaha) - -{ - LOG(0x1d,"bus_reset"); - - /* - * Clear bus descriptor - */ - eaha->wd.nactive = 0; - eaha_reset(eaha, TRUE); - eaha_init(eaha); - - printf("eaha: (%d) bus reset ", ++eaha->wd.reset_count); - delay(scsi_delay_after_reset); /* some targets take long to reset */ - - if (eaha->sc == 0) /* sanity */ - return; - - scsi_bus_was_reset(eaha->sc); -} - -#ifdef notdef - /* functions added to complete 1742 support, but not used. Untested. */ - - void eaha_download(port, data, len) - int port ; - char *data ; - unsigned len ; - { - /* 1744 firmware download. Not implemented. TRM6-21 */ - } - - void eaha_initscsi(data, len) - char *data ; - unsigned len ; - { - /* initialize SCSI subsystem. Presume BIOS does it. - Not implemented. TRM6-23 */ - } - - void eaha_noop() - { - /* Not implemented. TRM6-27 */ - } - - erccb *eaha_host_adapter_inquiry(eaha) /* Returns a promise */ - eaha_softc *eaha ; /* TRM6-31..33 */ - { - erccb *_erccb = erccb_alloc(eaha) ; - _erccb->_eccb.scather = (vm_offset_t) kvtophys(eaha->host_inquiry_data) ; - _erccb->_eccb.scathlen = sizeof(eaha->host_inquiry_data) ; - _erccb->_eccb.ses = 1 ; - _erccb->_eccb.command = EAHA_CMD_HOST_INQ ; - eaha_command(eaha->port,_erccb->_eccb,0) ; /* Is scsi_id used */ - return _erccb ; - } - - erccb *eaha_read_sense_info(eaha, target, lun) /* TRM 6-33..35 */ - eaha_softc *eaha ; - unsigned target, lun ; - { /* Don't think we need this because its done in scsi_alldevs.c */ - #ifdef notdef - erccb *_erccb = erccb_alloc(eaha) ; - _erccb->_eccb.command = EAHA_CMD_READ_SENS ; - _erccb->_eccb.lun = lun ; - eaha_command(eaha->port,_erccb->_eccb, target) ;/*Wrong # args*/ - return _erccb ; - #else - return 0 ; - #endif - } - - void eaha_diagnostic(eaha) - eaha_softc *eaha ; - { - /* Not implemented. TRM6-36..37 */ - } - - erccb *eaha_target_cmd(eaha, target, lun, data, len) /* TRM6-38..39 */ - eaha_softc *eaha ; - unsigned target, lun ; - char *data ; - unsigned len ; - { - erccb *_erccb = erccb_alloc(eaha) ; - _erccb->_eccb.command = EAHA_CMD_TARG_CMD ; - _erccb->_eccb.lun = lun ; - eaha_command(eaha->port,_erccb->_eccb,target);/*Wrong # args*/ - return _erccb ; - } - - erccb *eaha_init_cmd(port) /* SHOULD RETURN TOKEN. i.e. ptr to eccb */ - /* Need list of free eccbs */ - { /* to be continued,. possibly. */ - } - -#endif /* notdef */ - -target_info_t * -eaha_tgt_alloc( - eaha_softc_t eaha, - int id, - target_info_t *tgt) -{ - erccb *_erccb; - - if (tgt == 0) - tgt = scsi_slave_alloc(eaha - eaha_softc_data, id, eaha); - - _erccb = erccb_alloc(eaha) ; /* This is very dodgy */ - tgt->cmd_ptr = (char *)& _erccb->_eccb.cdb ; - tgt->dma_ptr = 0; - return tgt; -} - - -struct { - scsi_sense_data_t sns ; - unsigned char extra - [254-sizeof(scsi_sense_data_t)] ; -} eaha_xsns [NTARGETS] ;/*must be bss to be contiguous*/ - - -/* Enhanced adapter probe routine */ - -eaha_probe( - register int port, - struct bus_ctlr *ui) -{ - int unit = ui->unit; - eaha_softc_t eaha = &eaha_softc_data[unit] ; - int target_id ; - scsi_softc_t *sc ; - int s; - boolean_t did_banner = FALSE ; - struct aha_devs installed; - unsigned char my_scsi_id, my_interrupt ; - - if (unit >= NEAHA) - return(0); - - /* No interrupts yet */ - s = splbio(); - - /* - * Detect prescence of 174x in enhanced mode. Ignore HID2 and HID3 - * on the assumption that compatibility will be preserved. dph - */ - if (inb(HID0(port)) != 0x04 || inb(HID1(port)) != 0x90 || - (inb(PORTADDR(port)) & 0x80) != 0x80) { - splx(s); - return 0 ; - } - - /* Issue RESET in case this is a reboot */ - - outb(EBCTRL(port),0x04) ; /* Disable board. TRM4-12 */ - outb(PORTADDR(port),0x80) ; /* Disable standard mode ports. TRM4-13. */ - my_interrupt = inb(INTDEF(port)) & 0x07 ; - outb(INTDEF(port), my_interrupt | 0x00) ; - /* Disable interrupts. TRM4-15 */ - my_scsi_id = inb(SCSIDEF(port)) & 0x0f ; - outb(SCSIDEF(port), my_scsi_id | 0x10) ; - /* Force SCSI reset on hard reset. TRM4-16 */ - outb(G2CNTRL(port),0xe0) ; /* Reset board, clear interrupt */ - /* and set 'host ready'. */ - delay(10*10) ; /* HRST must remain set for 10us. TRM4-22 */ - /* (I don't believe the delay loop is slow enough.) */ - outb(G2CNTRL(port),0x60);/*Un-reset board, set 'host ready'. TRM4-22*/ - - printf("Adaptec 1740A/1742A/1744 enhanced mode\n"); - - /* Get host inquiry data */ - - eaha_softc_pool[unit] = eaha ; - bzero(eaha,sizeof(*eaha)) ; - eaha->port = port ; - - sc = scsi_master_alloc(unit, eaha) ; - eaha->sc = sc ; - sc->go = eaha_go ; - sc->watchdog = scsi_watchdog ; - sc->probe = eaha_probe_target ; - eaha->wd.reset = eaha_reset_scsibus ; - sc->max_dma_data = -1 ; /* Lets be optimistic */ - sc->initiator_id = my_scsi_id ; - eaha_reset(eaha,TRUE) ; - eaha->I_hold_my_phys_address = - kvtophys((vm_offset_t)&eaha->I_hold_my_phys_address) ; - { - erccb *e ; - eaha->toperccb = eaha->_erccbs ; - for (e=eaha->_erccbs; e < eaha->_erccbs+NECCBS; e++) { - e->next = e+1 ; - e->_eccb.status = - kvtophys((vm_offset_t) &e->status) ; - } - eaha->_erccbs[NECCBS-1].next = 0 ; - - } - - ui->sysdep1 = my_interrupt + 9 ; - take_ctlr_irq(ui) ; - - printf("%s%d: [port 0x%x intr ch %d] my SCSI id is %d", - ui->name, unit, port, my_interrupt + 9, my_scsi_id) ; - - outb(INTDEF(port), my_interrupt | 0x10) ; - /* Enable interrupts. TRM4-15 */ - outb(EBCTRL(port),0x01) ; /* Enable board. TRM4-12 */ - - { target_info_t *t = eaha_tgt_alloc(eaha, my_scsi_id, 0) ; - /* Haven't enabled target mode a la standard mode, because */ - /* it doesn't seem to be necessary. */ - sccpu_new_initiator(t, t) ; - } - - /* Find targets, incl. ourselves. */ - - for (target_id=0; target_id < SCSI_TARGETS; target_id++) - if (target_id != sc->initiator_id) { - scsi_cmd_test_unit_ready_t *cmd; - erccb *_erccb = erccb_alloc(eaha) ; - unsigned attempts = 0 ; -#define MAX_ATTEMPTS 2 - target_info_t temp_targ ; - - temp_targ.ior = 0 ; - temp_targ.hw_state = (char *) eaha ; - temp_targ.cmd_ptr = (char *) &_erccb->_eccb.cdb ; - temp_targ.target_id = target_id ; - temp_targ.lun = 0 ; - temp_targ.cur_cmd = SCSI_CMD_TEST_UNIT_READY; - - cmd = (scsi_cmd_test_unit_ready_t *) temp_targ.cmd_ptr; - - do { - cmd->scsi_cmd_code = SCSI_CMD_TEST_UNIT_READY; - cmd->scsi_cmd_lun_and_lba1 = 0; /*assume 1 lun?*/ - cmd->scsi_cmd_lba2 = 0; - cmd->scsi_cmd_lba3 = 0; - cmd->scsi_cmd_ss_flags = 0; - cmd->scsi_cmd_ctrl_byte = 0; /* not linked */ - - eaha_go( &temp_targ, - sizeof(scsi_cmd_test_unit_ready_t),0,0); - /* ints disabled, so call isr yourself. */ - while (temp_targ.done == SCSI_RET_IN_PROGRESS) - if (inb(G2STAT(eaha->port)) & 0x02) { - eaha_quiet = 1 ; - eaha_intr(unit) ; - eaha_quiet = 0 ; - } - if (temp_targ.done == SCSI_RET_NEED_SENSE) { - /* MUST get sense info : TRM6-34 */ - if (eaha_retrieve_sense_info( - eaha, temp_targ.target_id, - temp_targ.lun) && - attempts == MAX_ATTEMPTS-1) { - - printf( - "\nTarget %d Check Condition : " - ,temp_targ.target_id) ; - scsi_print_sense_data(&eaha_xsns - [temp_targ.target_id]); - printf("\n") ; - } - } - } while (temp_targ.done != SCSI_RET_SUCCESS && - temp_targ.done != SCSI_RET_ABORTED && - ++attempts < MAX_ATTEMPTS) ; - - /* - * Recognize target which is present, whether or not - * it is ready, e.g. drive with removable media. - */ - if (temp_targ.done == SCSI_RET_SUCCESS || - temp_targ.done == SCSI_RET_NEED_SENSE && - _erccb->status.target_status.bits != 0) { /* Eureka */ - installed.tgt_luns[target_id]=1;/*Assume 1 lun?*/ - printf(", %s%d", - did_banner++ ? "" : "target(s) at ", - target_id); - - erccb_free(eaha, _erccb) ; - - /* Normally, only LUN 0 */ - if (installed.tgt_luns[target_id] != 1) - printf("(%x)", installed.tgt_luns[target_id]); - /* - * Found a target - */ - (void) eaha_tgt_alloc(eaha, target_id, 0); - /* Why discard ? */ - } else - installed.tgt_luns[target_id]=0; - } - - printf(".\n") ; - splx(s); - return 1 ; -} - -int eaha_retrieve_sense_info ( - eaha_softc_t eaha, - int tid, - int lun) -{ - int result ; - int s ; - target_info_t dummy_target ; /* Keeps eaha_command() happy. HACK */ - erccb *_erccb1 = erccb_alloc(eaha) ; - - _erccb1->active_target = &dummy_target ; - dummy_target.target_id = tid ; - _erccb1->_eccb.command = - EAHA_CMD_READ_SENS ; - _erccb1->_eccb.lun = lun ; - _erccb1->_eccb.sense_p = kvtophys((vm_offset_t) &eaha_xsns [tid]); - _erccb1->_eccb.sense_len = sizeof(eaha_xsns [tid]); - _erccb1->_eccb.ses = 1 ; - s = splbio() ; - eaha_command(eaha->port,_erccb1) ; - while ((inb(G2STAT(eaha->port)) & 0x02) == 0) ; - outb(G2CNTRL(eaha->port),0x40);/* Clear int */ - splx(s) ; - result = _erccb1->status.target_status.bits != 0 ; - erccb_free(eaha,_erccb1) ; - return result ; -} - -/* - * Start a SCSI command on a target (enhanced mode) - */ -eaha_go( - target_info_t *tgt, - int cmd_count, - int in_count, - boolean_t cmd_only)/*lint: unused*/ -{ - eaha_softc_t eaha; - int s; - erccb *_erccb; - int len; - vm_offset_t virt; - int tid = tgt->target_id ; - -#ifdef CBUS - at386_io_lock_state(); -#endif - LOG(1,"go"); - -#ifdef CBUS - at386_io_lock(MP_DEV_WAIT); -#endif - eaha = (eaha_softc_t)tgt->hw_state; - - if(eaha->has_sense_info[tid]) { - (void) eaha_retrieve_sense_info - (eaha, tid, eaha->sense_info_lun[tid]) ; - eaha->has_sense_info[tid] = FALSE ; - if (tgt->cur_cmd == SCSI_CMD_REQUEST_SENSE) { - bcopy(&eaha_xsns[tid],tgt->cmd_ptr,in_count) ; - tgt->done = SCSI_RET_SUCCESS; - tgt->transient_state.cmd_count = cmd_count; - tgt->transient_state.out_count = 0; - tgt->transient_state.in_count = in_count; - /* Fake up interrupt */ - /* Highlights from eaha_initiator_intr(), */ - /* ignoring errors */ - if (tgt->ior) - (*tgt->dev_ops->restart)( tgt, TRUE); -#ifdef CBUS - at386_io_unlock(); -#endif - return ; - } - } - -/* XXX delay the handling of the ccb till later */ - _erccb = (erccb *) - ((unsigned)tgt->cmd_ptr - (unsigned) &((erccb *) 0)->_eccb.cdb); - /* Tell *rccb about target, eg. id ? */ - _erccb->active_target = tgt; - - /* - * We can do real DMA. - */ -/* tgt->transient_state.copy_count = 0; unused */ -/* tgt->transient_state.dma_offset = 0; unused */ - - tgt->transient_state.cmd_count = cmd_count; - - if ((tgt->cur_cmd == SCSI_CMD_WRITE) || - (tgt->cur_cmd == SCSI_CMD_LONG_WRITE)){ - io_req_t ior = tgt->ior; - register int len = ior->io_count; - - tgt->transient_state.out_count = len; - - /* How do we avoid leaks here ? Trust the board - will do zero-padding, for now. XXX CHECKME */ -#if 0 - if (len < tgt->block_size) { - bzero(to + len, tgt->block_size - len); - len = tgt->block_size; - tgt->transient_state.out_count = len; - } -#endif - } else { - tgt->transient_state.out_count = 0; - } - - /* See above for in_count < block_size */ - tgt->transient_state.in_count = in_count; - - /* - * Setup CCB state - */ - tgt->done = SCSI_RET_IN_PROGRESS; - - switch (tgt->cur_cmd) { - case SCSI_CMD_READ: - case SCSI_CMD_LONG_READ: - LOG(9,"readop"); - virt = (vm_offset_t)tgt->ior->io_data; - len = tgt->transient_state.in_count; - break; - case SCSI_CMD_WRITE: - case SCSI_CMD_LONG_WRITE: - LOG(0x1a,"writeop"); - virt = (vm_offset_t)tgt->ior->io_data; - len = tgt->transient_state.out_count; - break; - case SCSI_CMD_INQUIRY: - 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: - LOG(0x1c,"cmdop"); - LOG(0x80+tgt->cur_cmd,0); - virt = (vm_offset_t)tgt->cmd_ptr; - len = tgt->transient_state.in_count; - 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); - len = - tgt->transient_state.out_count = cmd_count - sizeof(scsi_command_group_0); - virt = (vm_offset_t)tgt->cmd_ptr+sizeof(scsi_command_group_0); - LOG(0x1c,"cmdop"); - LOG(0x80+tgt->cur_cmd,0); - break; - default: - LOG(0x1c,"cmdop"); - LOG(0x80+tgt->cur_cmd,0); - virt = 0; - len = 0; - } - - eaha_prepare_rccb(tgt, _erccb, virt, len); - - _erccb->_eccb.lun = tgt->lun; - - /* - * XXX here and everywhere, locks! - */ - s = splbio(); - - simple_lock(&eaha->aha_lock); - if (eaha->wd.nactive++ == 0) - eaha->wd.watchdog_state = SCSI_WD_ACTIVE; - simple_unlock(&eaha->aha_lock); - - LOG(3,"enqueue"); - - eaha_command(eaha->port, _erccb) ; - - splx(s); -#ifdef CBUS - at386_io_unlock(); -#endif -} - -eaha_prepare_rccb( - target_info_t *tgt, - erccb *_erccb, - vm_offset_t virt, - vm_size_t len) -{ - _erccb->_eccb.cdb_len = tgt->transient_state.cmd_count; - - _erccb->_eccb.command = EAHA_CMD_INIT_CMD;/* default common case */ - - if (virt == 0) { - /* no xfers */ - _erccb->_eccb.scather = 0 ; - _erccb->_eccb.scathlen = 0 ; - _erccb->_eccb.sg = 0 ; - } else { - /* messy xfer */ - scather_entry *seglist; - vm_size_t l1, off; - - _erccb->_eccb.sg = 1 ; - - if (tgt->dma_ptr == 0) - eaha_alloc_segment_list(tgt); - seglist = (scather_entry *) tgt->dma_ptr; - - _erccb->_eccb.scather = kvtophys((vm_offset_t) seglist); - - l1 = MACHINE_PGBYTES - (virt & (MACHINE_PGBYTES - 1)); - if (l1 > len) - l1 = len ; - - off = 1;/* now #pages */ - while (1) { - seglist->ptr = kvtophys(virt) ; - seglist->len = l1 ; - seglist++; - - if (len <= l1) - break ; - len-= l1 ; - virt += l1; off++; - - l1 = (len > MACHINE_PGBYTES) ? MACHINE_PGBYTES : len; - } - _erccb->_eccb.scathlen = off * sizeof(*seglist); - } -} - -/* - * Allocate dynamically segment lists to - * targets (for scatter/gather) - */ -vm_offset_t eaha_seglist_next = 0, eaha_seglist_end = 0 ; -#define EALLOC_SIZE (SCATHER_ENTRIES * sizeof(scather_entry)) - -eaha_alloc_segment_list( - target_info_t *tgt) -{ - -/* XXX locking */ -/* ? Can't spl() for unknown duration */ - if ((eaha_seglist_next + EALLOC_SIZE) > eaha_seglist_end) { - (void)kmem_alloc_wired(kernel_map,&eaha_seglist_next,PAGE_SIZE); - eaha_seglist_end = eaha_seglist_next + PAGE_SIZE; - } - tgt->dma_ptr = (char *)eaha_seglist_next; - eaha_seglist_next += EALLOC_SIZE; -/* XXX locking */ -} - -/* - * - * shameless copy from above - */ -eaha_reset_scsibus( - register eaha_softc_t eaha) -{ - register target_info_t *tgt; - register port = eaha->port; - register int i; - - for (i = 0; i < NECCBS; i++) { - tgt = eaha->_erccbs[i].active_target; - if (/*scsi_debug &&*/ tgt) - printf("Target %d was active, cmd x%x in x%x out x%x\n", - tgt->target_id, tgt->cur_cmd, - tgt->transient_state.in_count, - tgt->transient_state.out_count); - } - eaha_reset(eaha, FALSE); - delay(35); - /* no interrupt will come */ - eaha_bus_reset(eaha); -} - -boolean_t -eaha_probe_target( - target_info_t *tgt, - io_req_t ior) -{ - eaha_softc_t eaha = eaha_softc_pool[tgt->masterno]; - boolean_t newlywed; - - newlywed = (tgt->cmd_ptr == 0); - if (newlywed) { - /* desc was allocated afresh */ - (void) eaha_tgt_alloc(eaha,tgt->target_id, tgt); - } - - if (scsi_inquiry(tgt, SCSI_INQ_STD_DATA) == SCSI_RET_DEVICE_DOWN) - return FALSE; - - tgt->flags = TGT_ALIVE; - return TRUE; -} - - -/* - * Interrupt routine (enhanced mode) - * Take interrupts from the board - * - * Implementation: - * TBD - */ -eaha_intr( - int unit) -{ - register eaha_softc_t eaha; - register port; - unsigned g2intst, g2stat, g2stat2 ; - vm_offset_t mbi ; - erccb *_erccb ; - status_block *status ; - -#if MAPPABLE - extern boolean_t rz_use_mapped_interface; - - if (rz_use_mapped_interface) { - EAHA_intr(unit); - return ; - } -#endif /*MAPPABLE*/ - - eaha = eaha_softc_pool[unit]; - port = eaha->port; - - LOG(5,"\n\tintr"); -gotintr: - /* collect ephemeral information */ - - g2intst = inb(G2INTST(port)) ; /* See TRM4-22..23 */ - g2stat = inb(G2STAT(port)) ; /*lint:set,not used*/ - g2stat2 = inb(G2STAT2(port)) ; /*lint:set,not used*/ - mbi = (vm_offset_t) inb(MBOXIN0(port)) + (inb(MBOXIN1(port))<<8) + - (inb(MBOXIN2(port))<<16) + (inb(MBOXIN3(port))<<24) ; - - /* we got an interrupt allright */ - if (eaha->wd.nactive) - eaha->wd.watchdog_state = SCSI_WD_ACTIVE; - - outb(G2CNTRL(port),0x40) ; /* Clear EISA interrupt */ - - switch(g2intst>>4) { - case 0x07 : /* hardware error ? */ - case 0x0a : /* immediate command complete - don't expect */ - case 0x0e : /* ditto with failure */ - default : - printf( "aha%d: Bogus status (x%x) in MBI\n", - unit, mbi); - gimmeabreak() ; /* Any of above is disaster */ - break; - - case 0x0d : /* Asynchronous event TRM6-41 */ - if ((g2intst & 0x0f) == (inb(SCSIDEF(eaha->port)) & 0x0f)) - eaha_reset_scsibus(eaha) ; - else - eaha_target_intr(eaha, mbi, g2intst & 0x0f); - break; - - case 0x0c : /* ccb complete with error */ - case 0x01 : /* ccb completed with success */ - case 0x05 : /* ccb complete with success after retry */ - - _erccb = (erccb *) - ( ((vm_offset_t)&eaha->I_hold_my_phys_address) + - (mbi - eaha->I_hold_my_phys_address) - - (vm_offset_t)&(((erccb *)0)->_eccb) ) ; - /* That ain't necessary. As kernel (must be) */ - /* contiguous, only need delta to translate */ - - status = &_erccb->status ; - -#ifdef NOTDEF - if (!eaha_quiet && (!status->don || status->qf || - status->sc || status->dover || - status->ini || status->me)) { - printf("\nccb complete error G2INTST=%02X\n", - g2intst) ; - DUMP(*_erccb) ; - gimmeabreak() ; - } -#endif - - eaha_initiator_intr(eaha, _erccb); - break; - } - - /* See if more work ready */ - if (inb(G2STAT(port)) & 0x02) { - LOG(7,"\n\tre-intr"); - goto gotintr; - } -} - -/* - * The interrupt routine turns to one of these two - * functions, depending on the incoming mbi's role - */ -eaha_target_intr( - eaha_softc_t eaha, - unsigned int mbi, - unsigned int peer) -{ - target_info_t *initiator; /* this is the caller */ - target_info_t *self; /* this is us */ - int len; - - self = eaha->sc->target[eaha->sc->initiator_id]; - - initiator = eaha->sc->target[peer]; - - /* ..but initiators are not required to answer to our inquiry */ - if (initiator == 0) { - /* allocate */ - initiator = eaha_tgt_alloc(eaha, peer, 0); - - /* We do not know here wether the host was down when - we inquired, or it refused the connection. Leave - the decision on how we will talk to it to higher - level code */ - LOG(0xC, "new_initiator"); - sccpu_new_initiator(self, initiator); - /* Bug fix: was (aha->sc, self, initiator); dph */ - } - - /* The right thing to do would be build an ior - and call the self->dev_ops->strategy routine, - but we cannot allocate it at interrupt level. - Also note that we are now disconnected from the - initiator, no way to do anything else with it - but reconnect and do what it wants us to do */ - - /* obviously, this needs both spl and MP protection */ - self->dev_info.cpu.req_pending = TRUE; - self->dev_info.cpu.req_id = peer ; - self->dev_info.cpu.req_lun = (mbi>>24) & 0x07 ; - self->dev_info.cpu.req_cmd = - (mbi & 0x80000000) ? SCSI_CMD_SEND: SCSI_CMD_RECEIVE; - len = mbi & 0x00ffffff ; - - self->dev_info.cpu.req_len = len; - - LOG(0xB,"tgt-mode-restart"); - (*self->dev_ops->restart)( self, FALSE); - - /* The call above has either prepared the data, - placing an ior on self, or it handled it some - other way */ - if (self->ior == 0) - return; /* I guess we'll do it later */ - - { - erccb *_erccb ; - - _erccb = erccb_alloc(eaha) ; - _erccb->active_target = initiator; - _erccb->_eccb.command = EAHA_CMD_TARG_CMD ; - _erccb->_eccb.ses = 1 ; - _erccb->_eccb.dir = (self->cur_cmd == SCSI_CMD_SEND) ? 1 : 0 ; - - eaha_prepare_rccb(initiator, _erccb, - (vm_offset_t)self->ior->io_data, self->ior->io_count); - _erccb->_eccb.lun = initiator->lun; - - simple_lock(&eaha->aha_lock); - if (eaha->wd.nactive++ == 0) - eaha->wd.watchdog_state = SCSI_WD_ACTIVE; - simple_unlock(&eaha->aha_lock); - - eaha_command(eaha->port, _erccb); - } -} - -eaha_initiator_intr( - eaha_softc_t eaha, - erccb *_erccb) -{ - scsi2_status_byte_t status; - target_info_t *tgt; - - tgt = _erccb->active_target; - _erccb->active_target = 0; - - /* shortcut (sic!) */ - if (_erccb->status.ha_status == HA_STATUS_SUCCESS) - goto allok; - - switch (_erccb->status.ha_status) { /* TRM6-17 */ - case HA_STATUS_SUCCESS : -allok: - status = _erccb->status.target_status ; - if (status.st.scsi_status_code != SCSI_ST_GOOD) { - scsi_error(tgt, SCSI_ERR_STATUS, status.bits, 0); - tgt->done = (status.st.scsi_status_code == SCSI_ST_BUSY) ? - SCSI_RET_RETRY : SCSI_RET_NEED_SENSE; - } else - tgt->done = SCSI_RET_SUCCESS; - break; - - case HA_STATUS_SEL_TIMEOUT : - if (tgt->flags & TGT_FULLY_PROBED) - tgt->flags = 0; /* went offline */ - tgt->done = SCSI_RET_DEVICE_DOWN; - break; - - case HA_STATUS_OVRUN : - /* BUT we don't know if this is an underrun. - It is ok if we get less data than we asked - for, in a number of cases. Most boards do not - seem to generate this anyways, but some do. */ - { register int cmd = tgt->cur_cmd; - switch (cmd) { - case SCSI_CMD_INQUIRY: - case SCSI_CMD_REQUEST_SENSE: - case SCSI_CMD_RECEIVE_DIAG_RESULTS: - case SCSI_CMD_MODE_SENSE: - if (_erccb->status.du) /*Ignore underrun only*/ - break; - default: - printf("eaha: U/OVRUN on scsi command x%x\n",cmd); - gimmeabreak(); - } - } - goto allok; - case HA_STATUS_BUS_FREE : - printf("aha: bad disconnect\n"); - tgt->done = SCSI_RET_ABORTED; - break; - case HA_STATUS_PHASE_ERROR : - /* we'll get an interrupt soon */ - printf("aha: bad PHASE sequencing\n"); - tgt->done = SCSI_RET_ABORTED; - break; - case HA_STATUS_BAD_OPCODE : -printf("aha: BADCCB\n");gimmeabreak(); - tgt->done = SCSI_RET_RETRY; - break; - - case HA_STATUS_HOST_ABORTED : - case HA_STATUS_ADP_ABORTED : - case HA_STATUS_NO_FIRM : - case HA_STATUS_NOT_TARGET : - case HA_STATUS_INVALID_LINK : /* These aren't expected. */ - case HA_STATUS_BAD_CBLOCK : - case HA_STATUS_DUP_CBLOCK : - case HA_STATUS_BAD_SCATHER : - case HA_STATUS_RSENSE_FAIL : - case HA_STATUS_TAG_REJECT : - case HA_STATUS_HARD_ERROR : - case HA_STATUS_TARGET_NOATTN : - case HA_STATUS_HOST_RESET : - case HA_STATUS_OTHER_RESET : - case HA_STATUS_PROG_BAD_SUM : - default : - printf("aha: bad ha_status (x%x)\n", _erccb->status.ha_status); - tgt->done = SCSI_RET_ABORTED; - break; - } - - eaha->has_sense_info [tgt->target_id] = - (tgt->done == SCSI_RET_NEED_SENSE) ; - if (eaha->has_sense_info [tgt->target_id]) - eaha->sense_info_lun [tgt->target_id] = tgt->lun ; - - LOG(8,"end"); - - simple_lock(&eaha->aha_lock); - if (eaha->wd.nactive-- == 1) - eaha->wd.watchdog_state = SCSI_WD_INACTIVE; - simple_unlock(&eaha->aha_lock); - - if (tgt->ior) { - LOG(0xA,"ops->restart"); - (*tgt->dev_ops->restart)( tgt, TRUE); - } - - return FALSE;/*lint: Always returns FALSE. ignored. */ -} - -#endif /* NEAHA > 0 */ |