diff --git a/sys/dev/pci/trm.c b/sys/dev/pci/trm.c index 16d472d5163c..609eefb4ef2a 100644 --- a/sys/dev/pci/trm.c +++ b/sys/dev/pci/trm.c @@ -1,9 +1,10 @@ -/* $NetBSD: trm.c,v 1.6 2001/12/16 04:18:42 tsutsui Exp $ */ +/* $NetBSD: trm.c,v 1.7 2002/03/06 12:32:49 tsutsui Exp $ */ /* * Device Driver for Tekram DC395U/UW/F, DC315/U * PCI SCSI Bus Master Host Adapter * (SCSI chip set used Tekram ASIC TRM-S1040) * + * Copyright (c) 2002 Izumi Tsutsui * Copyright (c) 2001 Rui-Xiang Guo * All rights reserved. * @@ -41,9 +42,15 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: trm.c,v 1.6 2001/12/16 04:18:42 tsutsui Exp $"); +__KERNEL_RCSID(0, "$NetBSD: trm.c,v 1.7 2002/03/06 12:32:49 tsutsui Exp $"); /* #define TRM_DEBUG */ +#ifdef TRM_DEBUG +int trm_debug = 1; +#define DPRINTF(arg) if (trm_debug > 0) printf arg; +#else +#define DPRINTF(arg) +#endif #include #include @@ -51,6 +58,7 @@ __KERNEL_RCSID(0, "$NetBSD: trm.c,v 1.6 2001/12/16 04:18:42 tsutsui Exp $"); #include #include #include +#include #include #include @@ -71,8 +79,12 @@ __KERNEL_RCSID(0, "$NetBSD: trm.c,v 1.6 2001/12/16 04:18:42 tsutsui Exp $"); * feature of chip set MAX value */ #define TRM_MAX_TARGETS 16 +#define TRM_MAX_LUNS 8 #define TRM_MAX_SG_ENTRIES (MAXPHYS / PAGE_SIZE + 1) -#define TRM_MAX_SRB 32 +#define TRM_MAX_SRB 32 /* XXX */ +#define TRM_MAX_TAG TRM_MAX_SRB /* XXX */ +#define TRM_MAX_OFFSET 15 +#define TRM_MAX_PERIOD 125 /* * Segment Entry @@ -141,7 +153,7 @@ struct trm_nvram { #define NO_SEEK 0x00000010 #define LUN_CHECK 0x00000020 -#define trm_wait_30us() DELAY(30) +#define trm_eeprom_wait() DELAY(30) /* *----------------------------------------------------------------------- @@ -149,8 +161,7 @@ struct trm_nvram { *----------------------------------------------------------------------- */ struct trm_srb { - struct trm_srb *next; - struct trm_dcb *dcb; + TAILQ_ENTRY(trm_srb) next; struct trm_sg_entry *sgentry; struct scsipi_xfer *xs; /* scsipi_xfer for this cmd */ @@ -160,30 +171,9 @@ struct trm_srb { u_int32_t buflen; /* Total xfer length */ u_int32_t sgaddr; /* SGList physical starting address */ - u_int state; /* SRB State */ -#define SRB_FREE 0x0000 -#define SRB_WAIT 0x0001 -#define SRB_READY 0x0002 -#define SRB_MSGOUT 0x0004 /* arbitration+msg_out 1st byte */ -#define SRB_MSGIN 0x0008 -#define SRB_EXTEND_MSGIN 0x0010 -#define SRB_COMMAND 0x0020 -#define SRB_START_ 0x0040 /* arbitration+msg_out+command_out */ -#define SRB_DISCONNECT 0x0080 -#define SRB_DATA_XFER 0x0100 -#define SRB_XFERPAD 0x0200 -#define SRB_STATUS 0x0400 -#define SRB_COMPLETED 0x0800 -#define SRB_ABORT_SENT 0x1000 -#define SRB_DO_SYNC_NEGO 0x2000 -#define SRB_DO_WIDE_NEGO 0x4000 -#define SRB_UNEXPECT_RESEL 0x8000 - u_int8_t *msg; - int sgcnt; int sgindex; - int phase; /* SCSI phase */ int hastat; /* Host Adapter Status */ #define H_STATUS_GOOD 0x00 #define H_SEL_TIMEOUT 0x11 @@ -198,71 +188,43 @@ struct trm_srb { #define H_ABORT 0xFF int tastat; /* Target SCSI Status Byte */ int flag; /* SRBFlag */ -#define DATAOUT 0x0080 -#define DATAIN 0x0040 -#define RESIDUAL_VALID 0x0020 -#define ENABLE_TIMER 0x0010 -#define RESET_DEV0 0x0004 -#define ABORT_DEV 0x0002 #define AUTO_REQSENSE 0x0001 - int srbstat; /* SRB Status */ -#define SRB_OK 0x01 -#define ABORTION 0x02 -#define OVER_RUN 0x04 -#define UNDER_RUN 0x08 -#define PARITY_ERROR 0x10 -#define SRB_ERROR 0x20 - int tagnum; /* Tag number */ - int msgcnt; +#define PARITY_ERROR 0x0002 +#define SRB_TIMEOUT 0x0004 int cmdlen; /* SCSI command length */ u_int8_t cmd[12]; /* SCSI command */ - u_int8_t msgin[6]; - u_int8_t msgout[6]; + u_int8_t tag[2]; }; /* - *----------------------------------------------------------------------- - * Device Control Block - *----------------------------------------------------------------------- + * some info about each target and lun on the SCSI bus */ -struct trm_dcb { - struct trm_dcb *next; +struct trm_linfo { + int used; /* number of slots in use */ + int avail; /* where to start scanning */ + int busy; /* lun in use */ + struct trm_srb *untagged; + struct trm_srb *queued[TRM_MAX_TAG]; +}; - struct trm_srb *waitsrb; - struct trm_srb *last_waitsrb; +struct trm_tinfo { + u_int flag; /* Sync mode ? (1 sync):(0 async) */ +#define SYNC_NEGO_ENABLE 0x0001 +#define SYNC_NEGO_DOING 0x0002 +#define SYNC_NEGO_DONE 0x0004 +#define WIDE_NEGO_ENABLE 0x0008 +#define WIDE_NEGO_DOING 0x0010 +#define WIDE_NEGO_DONE 0x0020 +#define USE_TAG_QUEUING 0x0040 +#define NO_RESELECT 0x0080 + struct trm_linfo *linfo[TRM_MAX_LUNS]; - struct trm_srb *gosrb; - struct trm_srb *last_gosrb; - - struct trm_srb *actsrb; - - int gosrb_cnt; - u_int maxcmd; /* Max command */ - - int id; /* SCSI Target ID (SCSI Only) */ - int lun; /* SCSI Log. Unit (SCSI Only) */ - - u_int8_t tagmask; /* Tag mask */ - - u_int8_t tacfg; /* Target Config */ - u_int8_t idmsg; /* Identify Msg */ + u_int8_t config0; /* Target Config */ u_int8_t period; /* Max Period for nego. */ - u_int8_t synctl; /* Sync control for reg. */ u_int8_t offset; /* Sync offset for reg. and nego.(low nibble) */ - u_int8_t mode; /* Sync mode ? (1 sync):(0 async) */ -#define SYNC_NEGO_ENABLE 0x01 -#define SYNC_NEGO_DONE 0x02 -#define WIDE_NEGO_ENABLE 0x04 -#define WIDE_NEGO_DONE 0x08 -#define EN_TAG_QUEUING 0x10 -#define EN_ATN_STOP 0x20 -#define SYNC_NEGO_OFFSET 15 - u_int8_t flag; -#define ABORT_DEV_ 0x01 -#define SHOW_MESSAGE_ 0x02 }; /* @@ -278,20 +240,16 @@ struct trm_softc { bus_dma_tag_t sc_dmat; bus_dmamap_t sc_dmamap; /* Map the control structures */ - struct trm_dcb *sc_linkdcb; - struct trm_dcb *sc_roundcb; + struct trm_srb *sc_actsrb; + struct trm_tinfo sc_tinfo[TRM_MAX_TARGETS]; - struct trm_dcb *sc_actdcb; - struct trm_dcb *sc_dcb[TRM_MAX_TARGETS][8]; - - struct trm_srb *sc_freesrb; + TAILQ_HEAD(, trm_srb) sc_freesrb, + sc_readysrb; struct trm_srb *sc_srb; /* SRB array */ - struct trm_srb sc_tempsrb; struct trm_sg_entry *sc_sglist; - int maxid; - int maxtag; /* Max Tag number */ + int sc_maxid; /* * Link to the generic SCSI driver */ @@ -300,26 +258,45 @@ struct trm_softc { int sc_id; /* Adapter SCSI Target ID */ - int devcnt; /* Device Count */ + int sc_state; /* SRB State */ +#define TRM_IDLE 0 +#define TRM_WAIT 1 +#define TRM_READY 2 +#define TRM_MSGOUT 3 /* arbitration+msg_out 1st byte */ +#define TRM_MSGIN 4 +#define TRM_EXTEND_MSGIN 5 +#define TRM_COMMAND 6 +#define TRM_START 7 /* arbitration+msg_out+command_out */ +#define TRM_DISCONNECTED 8 +#define TRM_DATA_XFER 9 +#define TRM_XFERPAD 10 +#define TRM_STATUS 11 +#define TRM_COMPLETED 12 +#define TRM_ABORT_SENT 13 +#define TRM_UNEXPECT_RESEL 14 - int devflag[TRM_MAX_TARGETS][8]; /* flag of initDCB for device */ - - int devscan[TRM_MAX_TARGETS][8]; - int devscan_end; - int cur_offset; /* Current Sync offset */ - - struct trm_nvram sc_eeprom; + int sc_phase; /* SCSI phase */ int sc_config; -#define HCC_WIDE_CARD 0x20 -#define HCC_SCSI_RESET 0x10 -#define HCC_PARITY 0x08 -#define HCC_AUTOTERM 0x04 -#define HCC_LOW8TERM 0x02 -#define HCC_UP8TERM 0x01 +#define HCC_WIDE_CARD 0x01 +#define HCC_SCSI_RESET 0x02 +#define HCC_PARITY 0x04 +#define HCC_AUTOTERM 0x08 +#define HCC_LOW8TERM 0x10 +#define HCC_UP8TERM 0x20 + int sc_flag; #define RESET_DEV 0x01 #define RESET_DETECT 0x02 #define RESET_DONE 0x04 +#define WAIT_TAGMSG 0x08 /* XXX */ + + int sc_msgcnt; + + int resel_target; /* XXX */ + int resel_lun; /* XXX */ + + u_int8_t *sc_msg; + u_int8_t sc_msgbuf[6]; }; /* @@ -331,283 +308,363 @@ struct trm_softc { #define SCSI_BUS_RST_DETECT 0xFE /* Scsi Bus Reset detected */ #define SCSI_SEL_TIMEOUT 0xFF /* Selection Time out */ -static void trm_rewait_srb(struct trm_dcb *, struct trm_srb *); -static void trm_wait_srb(struct trm_softc *); -static void trm_reset_device(struct trm_softc *); -static void trm_recover_srb(struct trm_softc *); -static int trm_start_scsi(struct trm_softc *, struct trm_dcb *, - struct trm_srb *); +static int trm_probe(struct device *, struct cfdata *, void *); +static void trm_attach(struct device *, struct device *, void *); + +static int trm_init(struct trm_softc *); + +static void trm_scsipi_request(struct scsipi_channel *, scsipi_adapter_req_t, + void *); +static void trm_update_xfer_mode(struct trm_softc *, int); +static void trm_sched(struct trm_softc *); +static int trm_select(struct trm_softc *, struct trm_srb *); +static void trm_reset(struct trm_softc *); +static void trm_timeout(void *); static int trm_intr(void *); -static void trm_dataout_phase0(struct trm_softc *, struct trm_srb *, int *); -static void trm_datain_phase0(struct trm_softc *, struct trm_srb *, int *); -static void trm_command_phase0(struct trm_softc *, struct trm_srb *, int *); -static void trm_status_phase0(struct trm_softc *, struct trm_srb *, int *); -static void trm_msgout_phase0(struct trm_softc *, struct trm_srb *, int *); -static void trm_msgin_phase0(struct trm_softc *, struct trm_srb *, int *); -static void trm_dataout_phase1(struct trm_softc *, struct trm_srb *, int *); -static void trm_datain_phase1(struct trm_softc *, struct trm_srb *, int *); -static void trm_command_phase1(struct trm_softc *, struct trm_srb *, int *); -static void trm_status_phase1(struct trm_softc *, struct trm_srb *, int *); -static void trm_msgout_phase1(struct trm_softc *, struct trm_srb *, int *); -static void trm_msgin_phase1(struct trm_softc *, struct trm_srb *, int *); -static void trm_nop0(struct trm_softc *, struct trm_srb *, int *); -static void trm_nop1(struct trm_softc *, struct trm_srb *, int *); +static void trm_dataout_phase0(struct trm_softc *, int); +static void trm_datain_phase0(struct trm_softc *, int); +static void trm_status_phase0(struct trm_softc *); +static void trm_msgin_phase0(struct trm_softc *); +static void trm_command_phase1(struct trm_softc *); +static void trm_status_phase1(struct trm_softc *); +static void trm_msgout_phase1(struct trm_softc *); +static void trm_msgin_phase1(struct trm_softc *); -static void trm_set_xfer_rate(struct trm_softc *, struct trm_srb *, - struct trm_dcb *); -static void trm_dataio_xfer(struct trm_softc *, struct trm_srb *, int); +static void trm_dataio_xfer(struct trm_softc *, int); static void trm_disconnect(struct trm_softc *); static void trm_reselect(struct trm_softc *); -static void trm_srb_done(struct trm_softc *, struct trm_dcb *, - struct trm_srb *); -static void trm_doing_srb_done(struct trm_softc *); +static void trm_done(struct trm_softc *, struct trm_srb *); +static int trm_request_sense(struct trm_softc *, struct trm_srb *); +static void trm_dequeue(struct trm_softc *, struct trm_srb *); + static void trm_scsi_reset_detect(struct trm_softc *); static void trm_reset_scsi_bus(struct trm_softc *); -static int trm_request_sense(struct trm_softc *, struct trm_dcb *, - struct trm_srb *); -static void trm_msgout_abort(struct trm_softc *, struct trm_srb *); -static void trm_timeout(void *); -static void trm_reset(struct trm_softc *); -static void trm_send_srb(struct scsipi_xfer *, struct trm_softc *, - struct trm_srb *); -static int trm_init(struct trm_softc *); -static void trm_init_adapter(struct trm_softc *); -static void trm_init_dcb(struct trm_softc *, struct trm_dcb *, - struct scsipi_xfer *); -static void trm_link_srb(struct trm_softc *); -static void trm_init_sc(struct trm_softc *); -static void trm_check_eeprom(struct trm_softc *, struct trm_nvram *); -static void trm_release_srb(struct trm_softc *, struct trm_dcb *, - struct trm_srb *); -void trm_scsipi_request(struct scsipi_channel *, scsipi_adapter_req_t, void *); +static void trm_check_eeprom(struct trm_softc *, struct trm_nvram *); static void trm_eeprom_read_all(struct trm_softc *, struct trm_nvram *); static void trm_eeprom_write_all(struct trm_softc *, struct trm_nvram *); static void trm_eeprom_set_data(struct trm_softc *, u_int8_t, u_int8_t); static void trm_eeprom_write_cmd(struct trm_softc *, u_int8_t, u_int8_t); static u_int8_t trm_eeprom_get_data(struct trm_softc *, u_int8_t); -static int trm_probe(struct device *, struct cfdata *, void *); -static void trm_attach(struct device *, struct device *, void *); - struct cfattach trm_ca = { sizeof(struct trm_softc), trm_probe, trm_attach }; - -/* - * state_v = (void *) trm_scsi_phase0[phase] - */ -static void *trm_scsi_phase0[] = { - trm_dataout_phase0, /* phase:0 */ - trm_datain_phase0, /* phase:1 */ - trm_command_phase0, /* phase:2 */ - trm_status_phase0, /* phase:3 */ - trm_nop0, /* phase:4 */ - trm_nop1, /* phase:5 */ - trm_msgout_phase0, /* phase:6 */ - trm_msgin_phase0, /* phase:7 */ -}; - -/* - * state_v = (void *) trm_scsi_phase1[phase] - */ -static void *trm_scsi_phase1[] = { - trm_dataout_phase1, /* phase:0 */ - trm_datain_phase1, /* phase:1 */ - trm_command_phase1, /* phase:2 */ - trm_status_phase1, /* phase:3 */ - trm_nop0, /* phase:4 */ - trm_nop1, /* phase:5 */ - trm_msgout_phase1, /* phase:6 */ - trm_msgin_phase1, /* phase:7 */ -}; - /* real period: */ static const u_int8_t trm_clock_period[] = { - 12, /* 48 ns 20.0 MB/sec */ - 18, /* 72 ns 13.3 MB/sec */ - 25, /* 100 ns 10.0 MB/sec */ - 31, /* 124 ns 8.0 MB/sec */ - 37, /* 148 ns 6.6 MB/sec */ - 43, /* 172 ns 5.7 MB/sec */ - 50, /* 200 ns 5.0 MB/sec */ - 62 /* 248 ns 4.0 MB/sec */ + 12, /* 48 ns 20.0 MB/sec */ + 18, /* 72 ns 13.3 MB/sec */ + 25, /* 100 ns 10.0 MB/sec */ + 31, /* 124 ns 8.0 MB/sec */ + 37, /* 148 ns 6.6 MB/sec */ + 43, /* 172 ns 5.7 MB/sec */ + 50, /* 200 ns 5.0 MB/sec */ + 62 /* 248 ns 4.0 MB/sec */ }; +#define NPERIOD (sizeof(trm_clock_period)/sizeof(trm_clock_period[0])) + +static int +trm_probe(parent, match, aux) + struct device *parent; + struct cfdata *match; + void *aux; +{ + struct pci_attach_args *pa = aux; + + if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_TEKRAM2) + switch (PCI_PRODUCT(pa->pa_id)) { + case PCI_PRODUCT_TEKRAM2_DC315: + return (1); + } + return (0); +} /* - * Q back to pending Q + * attach and init a host adapter */ static void -trm_rewait_srb(dcb, srb) - struct trm_dcb *dcb; - struct trm_srb *srb; +trm_attach(parent, self, aux) + struct device *parent; + struct device *self; + void *aux; { - struct trm_srb *psrb1; - int s; - - s = splbio(); - - dcb->gosrb_cnt--; - psrb1 = dcb->gosrb; - if (srb == psrb1) - dcb->gosrb = psrb1->next; - else { - while (srb != psrb1->next) - psrb1 = psrb1->next; - - psrb1->next = srb->next; - if (srb == dcb->last_gosrb) - dcb->last_gosrb = psrb1; - } - if (dcb->waitsrb) { - srb->next = dcb->waitsrb; - dcb->waitsrb = srb; - } else { - srb->next = NULL; - dcb->waitsrb = srb; - dcb->last_waitsrb = srb; - } - dcb->tagmask &= ~(1 << srb->tagnum); /* Free TAG number */ - - splx(s); -} - -static void -trm_wait_srb(sc) - struct trm_softc *sc; -{ - struct trm_dcb *ptr, *ptr1; - struct trm_srb *srb; - int s; - - s = splbio(); - - if (sc->sc_actdcb == NULL && - (sc->sc_flag & (RESET_DETECT | RESET_DONE | RESET_DEV)) == 0) { - ptr = sc->sc_roundcb; - if (ptr == NULL) { - ptr = sc->sc_linkdcb; - sc->sc_roundcb = ptr; - } - for (ptr1 = ptr; ptr1 != NULL;) { - sc->sc_roundcb = ptr1->next; - if (ptr1->maxcmd <= ptr1->gosrb_cnt || - (srb = ptr1->waitsrb) == NULL) { - if (sc->sc_roundcb == ptr) - break; - ptr1 = ptr1->next; - } else { - if (trm_start_scsi(sc, ptr1, srb) == 0) { - /* - * If trm_start_scsi return 0 : - * current interrupt status is - * interrupt enable. It's said that - * SCSI processor is unoccupied - */ - ptr1->gosrb_cnt++; - if (ptr1->last_waitsrb == srb) { - ptr1->waitsrb = NULL; - ptr1->last_waitsrb = NULL; - } else - ptr1->waitsrb = srb->next; - - srb->next = NULL; - if (ptr1->gosrb != NULL) - ptr1->last_gosrb->next = srb; - else - ptr1->gosrb = srb; - - ptr1->last_gosrb = srb; - } - break; - } - } - } - splx(s); -} - -static void -trm_send_srb(xs, sc, srb) - struct scsipi_xfer *xs; - struct trm_softc *sc; - struct trm_srb *srb; -{ - struct trm_dcb *dcb; - int s; - -#ifdef TRM_DEBUG - printf("trm_send_srb..........\n"); -#endif - s = splbio(); + struct pci_attach_args *const pa = aux; + struct trm_softc *sc = (struct trm_softc *)self; + bus_space_tag_t iot; + bus_space_handle_t ioh; + pci_intr_handle_t ih; + pcireg_t command; + const char *intrstr; /* - * now get the DCB from upper layer( OS ) + * These cards do not allow memory mapped accesses + * pa_pc: chipset tag + * pa_tag: pci tag */ - dcb = srb->dcb; - - if (dcb->maxcmd <= dcb->gosrb_cnt || - sc->sc_actdcb != NULL || - (sc->sc_flag & (RESET_DETECT | RESET_DONE | RESET_DEV))) { - if (dcb->waitsrb != NULL) { - dcb->last_waitsrb->next = srb; - dcb->last_waitsrb = srb; - srb->next = NULL; - } else { - dcb->waitsrb = srb; - dcb->last_waitsrb = srb; - } - splx(s); + command = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); + if ((command & (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MASTER_ENABLE)) != + (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MASTER_ENABLE)) { + command |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MASTER_ENABLE; + pci_conf_write(pa->pa_pc, pa->pa_tag, + PCI_COMMAND_STATUS_REG, command); + } + /* + * mask for get correct base address of pci IO port + */ + if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_IO, 0, + &iot, &ioh, NULL, NULL)) { + printf("%s: unable to map registers\n", sc->sc_dev.dv_xname); return; } - if (dcb->waitsrb != NULL) { - dcb->last_waitsrb->next = srb; - dcb->last_waitsrb = srb; - srb->next = NULL; - /* srb = GetWaitingSRB(dcb); */ - srb = dcb->waitsrb; - dcb->waitsrb = srb->next; - srb->next = NULL; - } - if (trm_start_scsi(sc, dcb, srb) == 0) { - /* - * If trm_start_scsi return 0: current interrupt status - * is interrupt enable. It's said that SCSI processor is - * unoccupied. - */ - dcb->gosrb_cnt++; /* stack waiting SRB */ - if (dcb->gosrb != NULL) { - dcb->last_gosrb->next = srb; - dcb->last_gosrb = srb; - } else { - dcb->gosrb = srb; - dcb->last_gosrb = srb; - } - } else { - /* - * If trm_start_scsi return 1: current interrupt status - * is interrupt disreenable. It's said that SCSI processor - * has more one SRB need to do we need reQ back SRB. - */ - if (dcb->waitsrb != NULL) { - srb->next = dcb->waitsrb; - dcb->waitsrb = srb; - } else { - srb->next = NULL; - dcb->waitsrb = srb; - dcb->last_waitsrb = srb; - } - } + /* + * test checksum of eeprom.. & initialize softc... + */ + sc->sc_iot = iot; + sc->sc_ioh = ioh; + sc->sc_dmat = pa->pa_dmat; - splx(s); + if (trm_init(sc) != 0) { + /* + * Error during initialization! + */ + printf(": Error during initialization\n"); + return; + } + /* + * Now try to attach all the sub-devices + */ + if ((sc->sc_config & HCC_WIDE_CARD) != 0) + printf(": Tekram DC395UW/F (TRM-S1040) Fast40 " + "Ultra Wide SCSI Adapter\n"); + else + printf(": Tekram DC395U, DC315/U (TRM-S1040) Fast20 " + "Ultra SCSI Adapter\n"); + + /* + * Now tell the generic SCSI layer about our bus. + * map and establish interrupt + */ + if (pci_intr_map(pa, &ih)) { + printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname); + return; + } + intrstr = pci_intr_string(pa->pa_pc, ih); + + if (pci_intr_establish(pa->pa_pc, ih, IPL_BIO, trm_intr, sc) == NULL) { + printf("%s: couldn't establish interrupt", sc->sc_dev.dv_xname); + if (intrstr != NULL) + printf(" at %s", intrstr); + printf("\n"); + return; + } + if (intrstr != NULL) + printf("%s: interrupting at %s\n", + sc->sc_dev.dv_xname, intrstr); + + sc->sc_adapter.adapt_dev = &sc->sc_dev; + sc->sc_adapter.adapt_nchannels = 1; + sc->sc_adapter.adapt_openings = TRM_MAX_SRB; + sc->sc_adapter.adapt_max_periph = TRM_MAX_SRB; + sc->sc_adapter.adapt_request = trm_scsipi_request; + sc->sc_adapter.adapt_minphys = minphys; + + sc->sc_channel.chan_adapter = &sc->sc_adapter; + sc->sc_channel.chan_bustype = &scsi_bustype; + sc->sc_channel.chan_channel = 0; + sc->sc_channel.chan_ntargets = sc->sc_maxid + 1; + sc->sc_channel.chan_nluns = 8; + sc->sc_channel.chan_id = sc->sc_id; + + config_found(&sc->sc_dev, &sc->sc_channel, scsiprint); } /* - * Called by GENERIC SCSI driver - * enqueues a SCSI command + * initialize the internal structures for a given SCSI host */ -void +static int +trm_init(sc) + struct trm_softc *sc; +{ + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + bus_dma_segment_t seg; + struct trm_nvram eeprom; + struct trm_srb *srb; + struct trm_tinfo *ti; + struct nvram_target *tconf; + int error, rseg, all_sgsize; + int i, target; + u_int8_t bval; + + DPRINTF(("\n")); + + /* + * allocate the space for all SCSI control blocks (SRB) for DMA memory + */ + all_sgsize = TRM_MAX_SRB * TRM_SG_SIZE; + if ((error = bus_dmamem_alloc(sc->sc_dmat, all_sgsize, PAGE_SIZE, + 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) { + printf(": unable to allocate SCSI REQUEST BLOCKS, " + "error = %d\n", error); + return (1); + } + if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, + all_sgsize, (caddr_t *) &sc->sc_sglist, + BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) { + printf(": unable to map SCSI REQUEST BLOCKS, " + "error = %d\n", error); + return (1); + } + if ((error = bus_dmamap_create(sc->sc_dmat, all_sgsize, 1, + all_sgsize, 0, BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) { + printf(": unable to create SRB DMA maps, " + "error = %d\n", error); + return (1); + } + if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, + sc->sc_sglist, all_sgsize, NULL, BUS_DMA_NOWAIT)) != 0) { + printf(": unable to load SRB DMA maps, " + "error = %d\n", error); + return (1); + } + DPRINTF(("all_sgsize=%x\n", all_sgsize)); + memset(sc->sc_sglist, 0, all_sgsize); + + /* + * EEPROM CHECKSUM + */ + trm_check_eeprom(sc, &eeprom); + + sc->sc_maxid = 7; + sc->sc_config = HCC_AUTOTERM | HCC_PARITY; + if (bus_space_read_1(iot, ioh, TRM_GEN_STATUS) & WIDESCSI) { + sc->sc_config |= HCC_WIDE_CARD; + sc->sc_maxid = 15; + } + if (eeprom.channel_cfg & NAC_POWERON_SCSI_RESET) + sc->sc_config |= HCC_SCSI_RESET; + + sc->sc_actsrb = NULL; + sc->sc_id = eeprom.scsi_id; + sc->sc_flag = 0; + + /* + * initialize and link all device's SRB queue of this adapter + */ + TAILQ_INIT(&sc->sc_freesrb); + TAILQ_INIT(&sc->sc_readysrb); + + sc->sc_srb = malloc(sizeof(struct trm_srb) * TRM_MAX_SRB, + M_DEVBUF, M_NOWAIT|M_ZERO); + DPRINTF(("all SRB size=%x\n", sizeof(struct trm_srb) * TRM_MAX_SRB)); + if (sc->sc_srb == NULL) { + printf(": can not allocate SRB\n"); + return (1); + } + + for (i = 0, srb = sc->sc_srb; i < TRM_MAX_SRB; i++) { + srb->sgentry = sc->sc_sglist + TRM_MAX_SG_ENTRIES * i; + srb->sgoffset = TRM_SG_SIZE * i; + srb->sgaddr = sc->sc_dmamap->dm_segs[0].ds_addr + srb->sgoffset; + /* + * map all SRB space to SRB_array + */ + if (bus_dmamap_create(sc->sc_dmat, + MAXPHYS, TRM_MAX_SG_ENTRIES, MAXPHYS, 0, + BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &srb->dmap)) { + printf(": unable to create DMA transfer map...\n", + sc->sc_dev.dv_xname); + free(sc->sc_srb, M_DEVBUF); + return (1); + } + TAILQ_INSERT_TAIL(&sc->sc_freesrb, srb, next); + srb++; + } + + /* + * initialize all target info structure + */ + for (target = 0; target < TRM_MAX_TARGETS; target++) { + ti = &sc->sc_tinfo[target]; + ti->synctl = 0; + ti->offset = 0; + tconf = &eeprom.target[target]; + ti->config0 = tconf->config0; + ti->period = trm_clock_period[tconf->period & 0x07]; + ti->flag = 0; + if ((ti->config0 & NTC_DO_WIDE_NEGO) != 0 && + (sc->sc_config & HCC_WIDE_CARD) != 0) + ti->flag |= WIDE_NEGO_ENABLE; + if ((ti->config0 & NTC_DO_SYNC_NEGO) != 0) + ti->flag |= SYNC_NEGO_ENABLE; + if ((ti->config0 & NTC_DO_DISCONNECT) != 0) { +#ifdef notyet + if ((ti->config0 & NTC_DO_TAG_QUEUING) != 0) + ti->flag |= USE_TAG_QUEUING; +#endif + } else + ti->flag |= NO_RESELECT; + + DPRINTF(("target %d: config0 = 0x%02x, period = 0x%02x", + target, ti->config0, ti->period)); + DPRINTF((", flag = 0x%02x\n", ti->flag)); + } + + /* program configuration 0 */ + bval = PHASELATCH | INITIATOR | BLOCKRST; + if ((sc->sc_config & HCC_PARITY) != 0) + bval |= PARITYCHECK; + bus_space_write_1(iot, ioh, TRM_SCSI_CONFIG0, bval); + + /* program configuration 1 */ + bus_space_write_1(iot, ioh, TRM_SCSI_CONFIG1, + ACTIVE_NEG | ACTIVE_NEGPLUS); + + /* 250ms selection timeout */ + bus_space_write_1(iot, ioh, TRM_SCSI_TIMEOUT, SEL_TIMEOUT); + + /* Mask all the interrupt */ + bus_space_write_1(iot, ioh, TRM_DMA_INTEN, 0); + bus_space_write_1(iot, ioh, TRM_SCSI_INTEN, 0); + + /* Reset SCSI module */ + bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_RSTMODULE); + + /* program Host ID */ + bus_space_write_1(iot, ioh, TRM_SCSI_HOSTID, sc->sc_id); + + /* set ansynchronous transfer */ + bus_space_write_1(iot, ioh, TRM_SCSI_OFFSET, 0); + + /* Trun LED control off */ + bus_space_write_2(iot, ioh, TRM_GEN_CONTROL, + bus_space_read_2(iot, ioh, TRM_GEN_CONTROL) & ~EN_LED); + + /* DMA config */ + bus_space_write_2(iot, ioh, TRM_DMA_CONFIG, + bus_space_read_2(iot, ioh, TRM_DMA_CONFIG) | DMA_ENHANCE); + + /* Clear pending interrupt status */ + bus_space_read_1(iot, ioh, TRM_SCSI_INTSTATUS); + + /* Enable SCSI interrupt */ + bus_space_write_1(iot, ioh, TRM_SCSI_INTEN, + EN_SELECT | EN_SELTIMEOUT | EN_DISCONNECT | EN_RESELECTED | + EN_SCSIRESET | EN_BUSSERVICE | EN_CMDDONE); + bus_space_write_1(iot, ioh, TRM_DMA_INTEN, EN_SCSIINTR); + + trm_reset(sc); + + return (0); +} + +/* + * enqueues a SCSI command + * called by the higher level SCSI driver + */ +static void trm_scsipi_request(chan, req, arg) struct scsipi_channel *chan; scsipi_adapter_req_t req; @@ -616,10 +673,9 @@ trm_scsipi_request(chan, req, arg) bus_space_tag_t iot; bus_space_handle_t ioh; struct trm_softc *sc; - struct trm_dcb *dcb = NULL; struct trm_srb *srb; struct scsipi_xfer *xs; - int error, i, id, lun, s; + int error, i, target, lun, s; sc = (struct trm_softc *)chan->chan_adapter->adapt_dev; iot = sc->sc_iot; @@ -628,37 +684,10 @@ trm_scsipi_request(chan, req, arg) switch (req) { case ADAPTER_REQ_RUN_XFER: xs = arg; - id = xs->xs_periph->periph_target; + target = xs->xs_periph->periph_target; lun = xs->xs_periph->periph_lun; -#ifdef TRM_DEBUG - printf("trm_scsipi_request.....\n"); - printf("%s: id= %d lun= %d\n", sc->sc_dev.dv_xname, id, lun); - printf("sc->devscan[id][lun]= %d\n", sc->devscan[id][lun]); -#endif - if ((id > sc->maxid) || (lun > 7)) { - xs->error = XS_DRIVER_STUFFUP; - return; - } - dcb = sc->sc_dcb[id][lun]; - if (sc->devscan[id][lun] != 0 && sc->devflag[id][lun] == 0) { - /* - * Scan SCSI BUS => trm_init_dcb - */ - if (sc->devcnt < TRM_MAX_TARGETS) { -#ifdef TRM_DEBUG - printf("trm_init_dcb: dcb=%8x, ", (int) dcb); - printf("ID=%2x, LUN=%2x\n", id, lun); -#endif - sc->devflag[id][lun] = 1; - trm_init_dcb(sc, dcb, xs); - } else { - printf("%s: ", sc->sc_dev.dv_xname); - printf("sc->devcnt >= TRM_MAX_TARGETS\n"); - xs->error = XS_DRIVER_STUFFUP; - return; - } - } - + DPRINTF(("trm_scsipi_request.....\n")); + DPRINTF(("target= %d lun= %d\n", target, lun)); if (xs->xs_control & XS_CTL_RESET) { trm_reset(sc); xs->error = XS_NOERROR | XS_RESET; @@ -668,46 +697,25 @@ trm_scsipi_request(chan, req, arg) printf("%s: Is it done?\n", sc->sc_dev.dv_xname); xs->xs_status &= ~XS_STS_DONE; } - xs->error = 0; - xs->status = 0; - xs->resid = 0; s = splbio(); /* Get SRB */ - srb = sc->sc_freesrb; + srb = TAILQ_FIRST(&sc->sc_freesrb); if (srb != NULL) { - sc->sc_freesrb = srb->next; - srb->next = NULL; -#ifdef TRM_DEBUG - printf("srb = %8p sc->sc_freesrb= %8p\n", - srb, sc->sc_freesrb); -#endif + TAILQ_REMOVE(&sc->sc_freesrb, srb, next); } else { xs->error = XS_RESOURCE_SHORTAGE; scsipi_done(xs); splx(s); return; } - /* - * XXX BuildSRB(srb ,dcb); XXX - */ - srb->dcb = dcb; + srb->xs = xs; srb->cmdlen = xs->cmdlen; - /* - * Move layer of CAM command block to layer of SCSI - * Request Block for SCSI processor command doing. - */ memcpy(srb->cmd, xs->cmd, xs->cmdlen); + if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) { -#ifdef TRM_DEBUG - printf("xs->datalen...\n"); - printf("sc->sc_dmat=%x\n", (int) sc->sc_dmat); - printf("srb->dmap=%x\n", (int) srb->dmap); - printf("xs->data=%x\n", (int) xs->data); - printf("xs->datalen=%x\n", (int) xs->datalen); -#endif if ((error = bus_dmamap_load(sc->sc_dmat, srb->dmap, xs->data, xs->datalen, NULL, ((xs->xs_control & XS_CTL_NOSLEEP) ? @@ -721,8 +729,7 @@ trm_scsipi_request(chan, req, arg) /* * free SRB */ - srb->next = sc->sc_freesrb; - sc->sc_freesrb = srb; + TAILQ_INSERT_TAIL(&sc->sc_freesrb, srb, next); splx(s); return; } @@ -749,34 +756,30 @@ trm_scsipi_request(chan, req, arg) bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, srb->sgoffset, TRM_SG_SIZE, BUS_DMASYNC_PREWRITE); + sc->sc_phase = PH_BUS_FREE; /* SCSI bus free Phase */ + srb->sgindex = 0; srb->hastat = 0; srb->tastat = 0; - srb->msgcnt = 0; - srb->srbstat = 0; srb->flag = 0; - srb->state = 0; - srb->phase = PH_BUS_FREE; /* SCSI bus free Phase */ - trm_send_srb(xs, sc, srb); + TAILQ_INSERT_TAIL(&sc->sc_readysrb, srb, next); + if (sc->sc_actsrb == NULL) + trm_sched(sc); splx(s); - if ((xs->xs_control & XS_CTL_POLL) == 0) { + if ((xs->xs_control & XS_CTL_POLL) != 0) { int timeout = xs->timeout; - timeout = (timeout > 100000) ? - timeout / 1000 * hz : timeout * hz / 1000; - callout_reset(&xs->xs_callout, timeout, - trm_timeout, srb); - } else { + s = splbio(); do { - while (--xs->timeout) { + while (--timeout) { DELAY(1000); if (bus_space_read_2(iot, ioh, TRM_SCSI_STATUS) & SCSIINTERRUPT) break; } - if (xs->timeout == 0) { + if (timeout == 0) { trm_timeout(srb); break; } else @@ -791,74 +794,249 @@ trm_scsipi_request(chan, req, arg) return; case ADAPTER_REQ_SET_XFER_MODE: - /* XXX XXX XXX */ - return; + { + struct trm_tinfo *ti; + struct scsipi_xfer_mode *xm; + + xm = arg; + ti = &sc->sc_tinfo[xm->xm_target]; + ti->flag &= ~(SYNC_NEGO_ENABLE|WIDE_NEGO_ENABLE); + +#ifdef notyet + if ((xm->xm_mode & PERIPH_CAP_TQING) != 0) + ti->flag |= USE_TAG_QUEUING; + else +#endif + ti->flag &= ~USE_TAG_QUEUING; + + if ((xm->xm_mode & PERIPH_CAP_WIDE16) != 0) { + ti->flag |= WIDE_NEGO_ENABLE; + ti->flag &= ~WIDE_NEGO_DONE; + } + + if ((xm->xm_mode & PERIPH_CAP_SYNC) != 0) { + ti->flag |= SYNC_NEGO_ENABLE; + ti->flag &= ~SYNC_NEGO_DONE; + ti->period = trm_clock_period[0]; + } + + /* + * If we're not going to negotiate, send the + * notification now, since it won't happen later. + */ + if ((ti->flag & (WIDE_NEGO_DONE|SYNC_NEGO_DONE)) == + (WIDE_NEGO_DONE|SYNC_NEGO_DONE)) + trm_update_xfer_mode(sc, xm->xm_target); + + return; + } } } static void -trm_reset_device(sc) +trm_update_xfer_mode(sc, target) struct trm_softc *sc; + int target; { - struct trm_dcb *dcb, *pdcb; - struct trm_nvram *eeprom; - int index; + struct scsipi_xfer_mode xm; + struct trm_tinfo *ti; - dcb = sc->sc_linkdcb; - if (dcb == NULL) - return; + ti = &sc->sc_tinfo[target]; + xm.xm_target = target; + xm.xm_mode = 0; + xm.xm_period = 0; + xm.xm_offset = 0; - pdcb = dcb; - do { - dcb->mode &= ~(SYNC_NEGO_DONE | WIDE_NEGO_DONE); - dcb->synctl = 0; - dcb->offset = 0; - eeprom = &sc->sc_eeprom; - dcb->tacfg = eeprom->target[dcb->id].config0; - index = eeprom->target[dcb->id].period & 0x07; - dcb->period = trm_clock_period[index]; - if ((dcb->tacfg & NTC_DO_WIDE_NEGO) && - (sc->sc_config & HCC_WIDE_CARD)) - dcb->mode |= WIDE_NEGO_ENABLE; + if ((ti->synctl & WIDE_SYNC) != 0) + xm.xm_mode |= PERIPH_CAP_WIDE16; - dcb = dcb->next; + if (ti->period > 0) { + xm.xm_mode |= PERIPH_CAP_SYNC; + xm.xm_period = ti->period; + xm.xm_offset = ti->offset; } - while (pdcb != dcb); + +#ifdef notyet + if ((ti->flag & USE_TAG_QUEUING) != 0) + xm.xm_mode |= PERIPH_CAP_TQING; +#endif + + scsipi_async_event(&sc->sc_channel, ASYNC_EVENT_XFER_MODE, &xm); } static void -trm_recover_srb(sc) +trm_sched(sc) struct trm_softc *sc; { - struct trm_dcb *dcb, *pdcb; - struct trm_srb *psrb, *psrb2; - int i; + struct trm_srb *srb; + struct scsipi_periph *periph; + struct trm_tinfo *ti; + struct trm_linfo *li; + int s, lun, tag; - dcb = sc->sc_linkdcb; - if (dcb == NULL) - return; + DPRINTF(("trm_sched...\n")); - pdcb = dcb; - do { - psrb = pdcb->gosrb; - for (i = 0; i < pdcb->gosrb_cnt; i++) { - psrb2 = psrb; - psrb = psrb->next; - if (pdcb->waitsrb) { - psrb2->next = pdcb->waitsrb; - pdcb->waitsrb = psrb2; + TAILQ_FOREACH(srb, &sc->sc_readysrb, next) { + periph = srb->xs->xs_periph; + ti = &sc->sc_tinfo[periph->periph_target]; + lun = periph->periph_lun; + + /* select type of tag for this command */ + if ((ti->flag & NO_RESELECT) != 0 || + (ti->flag & USE_TAG_QUEUING) == 0 || + (srb->flag & AUTO_REQSENSE) != 0 || + (srb->xs->xs_control & XS_CTL_REQSENSE) != 0) + tag = 0; + else + tag = srb->xs->xs_tag_type; +#if 0 + /* XXX use tags for polled commands? */ + if (srb->xs->xs_control & XS_CTL_POLL) + tag = 0; +#endif + + s = splbio(); + li = ti->linfo[lun]; + if (li == NULL) { + /* initialize lun info */ + if ((li = malloc(sizeof(*li), M_DEVBUF, + M_NOWAIT|M_ZERO)) == NULL) { + splx(s); + continue; + } + ti->linfo[lun] = li; + } + + if (tag == 0) { + /* try to issue this srb as an un-tagged command */ + if (li->untagged == NULL) + li->untagged = srb; + } + if (li->untagged != NULL) { + tag = 0; + if (li->busy != 1 && li->used == 0) { + /* we need to issue the untagged command now */ + srb = li->untagged; + periph = srb->xs->xs_periph; } else { - pdcb->waitsrb = psrb2; - pdcb->last_waitsrb = psrb2; - psrb2->next = NULL; + /* not ready yet */ + splx(s); + continue; } } - pdcb->gosrb_cnt = 0; - pdcb->gosrb = NULL; - pdcb->tagmask = 0; - pdcb = pdcb->next; + srb->tag[0] = tag; + if (tag != 0) { + li->queued[srb->xs->xs_tag_id] = srb; + srb->tag[1] = srb->xs->xs_tag_id; + li->used++; + } + + if (li->untagged != NULL && li->busy != 1) { + li->busy = 1; + TAILQ_REMOVE(&sc->sc_readysrb, srb, next); + sc->sc_actsrb = srb; + trm_select(sc, srb); + splx(s); + break; + } + if (li->untagged == NULL && tag != 0) { + TAILQ_REMOVE(&sc->sc_readysrb, srb, next); + sc->sc_actsrb = srb; + trm_select(sc, srb); + splx(s); + break; + } else + splx(s); } - while (pdcb != dcb); +} + +static int +trm_select(sc, srb) + struct trm_softc *sc; + struct trm_srb *srb; +{ + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + struct scsipi_periph *periph = srb->xs->xs_periph; + int target = periph->periph_target; + int lun = periph->periph_lun; + struct trm_tinfo *ti = &sc->sc_tinfo[target]; + u_int8_t scsicmd; + + DPRINTF(("trm_select.....\n")); + + if ((srb->xs->xs_control & XS_CTL_POLL) == 0) { + int timeout = srb->xs->timeout; + timeout = (timeout > 100000) ? + timeout / 1000 * hz : timeout * hz / 1000; + callout_reset(&srb->xs->xs_callout, timeout, trm_timeout, srb); + } + + bus_space_write_1(iot, ioh, TRM_SCSI_HOSTID, sc->sc_id); + bus_space_write_1(iot, ioh, TRM_SCSI_TARGETID, target); + bus_space_write_1(iot, ioh, TRM_SCSI_SYNC, ti->synctl); + bus_space_write_1(iot, ioh, TRM_SCSI_OFFSET, ti->offset); + /* Flush FIFO */ + bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_CLRFIFO); + DELAY(10); + + sc->sc_phase = PH_BUS_FREE; /* initial phase */ + + DPRINTF(("cmd = 0x%02x\n", srb->cmd[0])); + + if (((ti->flag & WIDE_NEGO_ENABLE) && + (ti->flag & WIDE_NEGO_DONE) == 0) || + ((ti->flag & SYNC_NEGO_ENABLE) && + (ti->flag & SYNC_NEGO_DONE) == 0)) { + sc->sc_state = TRM_MSGOUT; + bus_space_write_1(iot, ioh, TRM_SCSI_FIFO, + MSG_IDENTIFY(lun, 0)); + bus_space_write_multi_1(iot, ioh, + TRM_SCSI_FIFO, srb->cmd, srb->cmdlen); + /* it's important for atn stop */ + bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, + DO_DATALATCH | DO_HWRESELECT); + /* SCSI command */ + bus_space_write_1(iot, ioh, TRM_SCSI_COMMAND, SCMD_SEL_ATNSTOP); + DPRINTF(("select with SEL_ATNSTOP\n")); + return (0); + } + + if (srb->tag[0] != 0) { + /* Send identify message */ + bus_space_write_1(iot, ioh, TRM_SCSI_FIFO, + MSG_IDENTIFY(lun, 1)); + /* Send Tag id */ + bus_space_write_1(iot, ioh, TRM_SCSI_FIFO, srb->tag[0]); + bus_space_write_1(iot, ioh, TRM_SCSI_FIFO, srb->tag[1]); + scsicmd = SCMD_SEL_ATN3; + DPRINTF(("select with SEL_ATN3\n")); + } else { + /* Send identify message */ + bus_space_write_1(iot, ioh, TRM_SCSI_FIFO, + MSG_IDENTIFY(lun, + (ti->flag & NO_RESELECT) == 0 && + (srb->flag & AUTO_REQSENSE) == 0 && + (srb->xs->xs_control & XS_CTL_REQSENSE) == 0)); + scsicmd = SCMD_SEL_ATN; + DPRINTF(("select with SEL_ATN\n")); + } + sc->sc_state = TRM_START; + + /* + * Send CDB ..command block... + */ + bus_space_write_multi_1(iot, ioh, TRM_SCSI_FIFO, srb->cmd, srb->cmdlen); + + /* + * If trm_select return 0: current interrupt status + * is interrupt enable. It's said that SCSI processor is + * unoccupied. + */ + sc->sc_phase = PH_BUS_FREE; /* SCSI bus free Phase */ + /* SCSI command */ + bus_space_write_1(iot, ioh, TRM_SCSI_COMMAND, scsicmd); + return (0); } /* @@ -872,9 +1050,8 @@ trm_reset(sc) bus_space_handle_t ioh = sc->sc_ioh; int s; -#ifdef TRM_DEBUG - printf("%s: SCSI RESET.........", sc->sc_dev.dv_xname); -#endif + DPRINTF(("trm_reset.........\n")); + s = splbio(); /* disable SCSI and DMA interrupt */ @@ -882,7 +1059,7 @@ trm_reset(sc) bus_space_write_1(iot, ioh, TRM_SCSI_INTEN, 0); trm_reset_scsi_bus(sc); - DELAY(500000); + DELAY(100000); /* Enable SCSI interrupt */ bus_space_write_1(iot, ioh, TRM_SCSI_INTEN, @@ -898,11 +1075,8 @@ trm_reset(sc) /* Clear SCSI FIFO */ bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_CLRFIFO); - trm_reset_device(sc); - trm_doing_srb_done(sc); - sc->sc_actdcb = NULL; + sc->sc_actsrb = NULL; sc->sc_flag = 0; /* RESET_DETECT, RESET_DONE, RESET_DEV */ - trm_wait_srb(sc); splx(s); } @@ -927,300 +1101,201 @@ trm_timeout(arg) sc = (void *)periph->periph_channel->chan_adapter->adapt_dev; - s = splbio(); trm_reset_scsi_bus(sc); - callout_stop(&xs->xs_callout); + s = splbio(); + srb->flag |= SRB_TIMEOUT; + trm_done(sc, srb); + /* XXX needs more.. */ splx(s); } -static int -trm_start_scsi(sc, dcb, srb) - struct trm_softc *sc; - struct trm_dcb *dcb; - struct trm_srb *srb; -{ - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; - int tagnum; - u_int32_t tagmask; - u_int8_t scsicmd, idmsg; - - srb->tagnum = 31; - - bus_space_write_1(iot, ioh, TRM_SCSI_HOSTID, sc->sc_id); - bus_space_write_1(iot, ioh, TRM_SCSI_TARGETID, dcb->id); - bus_space_write_1(iot, ioh, TRM_SCSI_SYNC, dcb->synctl); - bus_space_write_1(iot, ioh, TRM_SCSI_OFFSET, dcb->offset); - srb->phase = PH_BUS_FREE; /* initial phase */ - /* Flush FIFO */ - bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_CLRFIFO); - - idmsg = dcb->idmsg; - - if ((srb->cmd[0] == INQUIRY) || - (srb->cmd[0] == REQUEST_SENSE)) { - if (((dcb->mode & WIDE_NEGO_ENABLE) && - (dcb->mode & WIDE_NEGO_DONE) == 0) || - ((dcb->mode & SYNC_NEGO_ENABLE) && - (dcb->mode & SYNC_NEGO_DONE) == 0)) { - if ((dcb->idmsg & 7) == 0 || srb->cmd[0] != INQUIRY) { - scsicmd = SCMD_SEL_ATNSTOP; - srb->state = SRB_MSGOUT; - goto polling; - } - } - /* Send identify message */ - bus_space_write_1(iot, ioh, TRM_SCSI_FIFO, - idmsg & ~MSG_IDENTIFY_DISCFLAG); - scsicmd = SCMD_SEL_ATN; - srb->state = SRB_START_; - } else { /* not inquiry,request sense,auto request sense */ - /* Send identify message */ - bus_space_write_1(iot, ioh, TRM_SCSI_FIFO, idmsg); - DELAY(30); - scsicmd = SCMD_SEL_ATN; - srb->state = SRB_START_; - if (dcb->mode & EN_TAG_QUEUING) { - /* Send Tag message, get tag id */ - tagmask = 1; - tagnum = 0; - while (tagmask & dcb->tagmask) { - tagmask = tagmask << 1; - tagnum++; - } - /* Send Tag id */ - bus_space_write_1(iot, ioh, TRM_SCSI_FIFO, - MSG_SIMPLE_Q_TAG); - bus_space_write_1(iot, ioh, TRM_SCSI_FIFO, tagnum); - - dcb->tagmask |= tagmask; - srb->tagnum = tagnum; - - scsicmd = SCMD_SEL_ATN3; - srb->state = SRB_START_; - } - } -polling: - /* - * Send CDB ..command block... - */ - bus_space_write_multi_1(iot, ioh, TRM_SCSI_FIFO, srb->cmd, srb->cmdlen); - - if (bus_space_read_2(iot, ioh, TRM_SCSI_STATUS) & SCSIINTERRUPT) { - /* - * If trm_start_scsi return 1: current interrupt status - * is interrupt disreenable. It's said that SCSI processor - * has more one SRB need to do, SCSI processor has been - * occupied by one SRB. - */ - srb->state = SRB_READY; - dcb->tagmask &= ~(1 << srb->tagnum); - return (1); - } else { - /* - * If trm_start_scsi return 0: current interrupt status - * is interrupt enable. It's said that SCSI processor is - * unoccupied. - */ - srb->phase = PH_BUS_FREE; /* SCSI bus free Phase */ - sc->sc_actdcb = dcb; - dcb->actsrb = srb; - bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, - DO_DATALATCH | DO_HWRESELECT); - /* it's important for atn stop */ - /* - * SCSI command - */ - bus_space_write_1(iot, ioh, TRM_SCSI_COMMAND, scsicmd); - return (0); - } -} - /* * Catch an interrupt from the adapter * Process pending device interrupts. */ static int -trm_intr(vsc) - void *vsc; +trm_intr(arg) + void *arg; { bus_space_tag_t iot; bus_space_handle_t ioh; struct trm_softc *sc; - struct trm_dcb *dcb; struct trm_srb *srb; - void (*state_v) (struct trm_softc *, struct trm_srb *, int *); - int phase, intstat, stat = 0; - -#ifdef TRM_DEBUG - printf("trm_intr......\n"); -#endif - sc = (struct trm_softc *)vsc; - iot = sc->sc_iot; - ioh = sc->sc_ioh; + int intstat, stat; + DPRINTF(("trm_intr......\n")); + sc = (struct trm_softc *)arg; if (sc == NULL) return (0); + iot = sc->sc_iot; + ioh = sc->sc_ioh; + stat = bus_space_read_2(iot, ioh, TRM_SCSI_STATUS); if ((stat & SCSIINTERRUPT) == 0) return (0); -#ifdef TRM_DEBUG - printf("stat=%2x,", stat); -#endif + DPRINTF(("stat = %04x, ", stat)); intstat = bus_space_read_1(iot, ioh, TRM_SCSI_INTSTATUS); -#ifdef TRM_DEBUG - printf("intstat=%2x,", intstat); -#endif + DPRINTF(("intstat=%02x, ", intstat)); if (intstat & (INT_SELTIMEOUT | INT_DISCONNECT)) { + DPRINTF(("\n")); trm_disconnect(sc); return (1); } if (intstat & INT_RESELECTED) { + DPRINTF(("\n")); trm_reselect(sc); return (1); } if (intstat & INT_SCSIRESET) { + DPRINTF(("\n")); trm_scsi_reset_detect(sc); return (1); } if (intstat & (INT_BUSSERVICE | INT_CMDDONE)) { - dcb = sc->sc_actdcb; - srb = dcb->actsrb; - if (dcb != NULL) - if (dcb->flag & ABORT_DEV_) { - srb->msgout[0] = MSG_ABORT; - trm_msgout_abort(sc, srb); - } + srb = sc->sc_actsrb; + DPRINTF(("sc->sc_phase = %2d, sc->sc_state = %2d\n", + sc->sc_phase, sc->sc_state)); /* * software sequential machine */ - phase = srb->phase; /* phase: */ /* - * 62037 or 62137 call trm_scsi_phase0[]... "phase - * entry" handle every phase before start transfer + * call phase0 functions... "phase entry" handle + * every phase before start transfer */ - state_v = (void *)trm_scsi_phase0[phase]; - state_v(sc, srb, &stat); + switch (sc->sc_phase) { + case PH_DATA_OUT: + trm_dataout_phase0(sc, stat); + break; + case PH_DATA_IN: + trm_datain_phase0(sc, stat); + break; + case PH_COMMAND: + break; + case PH_STATUS: + trm_status_phase0(sc); + stat = PH_BUS_FREE; + break; + case PH_MSG_OUT: + if (sc->sc_state == TRM_UNEXPECT_RESEL || + sc->sc_state == TRM_ABORT_SENT) + stat = PH_BUS_FREE; + break; + case PH_MSG_IN: + trm_msgin_phase0(sc); + stat = PH_BUS_FREE; + break; + case PH_BUS_FREE: + break; + default: + printf("%s: unexpected phase in trm_intr() phase0\n", + sc->sc_dev.dv_xname); + break; + } - /* - * if there were any exception occured - * stat will be modify to bus free phase new - * stat transfer out from ... prvious state_v - * - */ - /* phase:0,1,2,3,4,5,6,7 */ - srb->phase = stat & PHASEMASK; - phase = stat & PHASEMASK; + sc->sc_phase = stat & PHASEMASK; + + switch (sc->sc_phase) { + case PH_DATA_OUT: + trm_dataio_xfer(sc, XFERDATAOUT); + break; + case PH_DATA_IN: + trm_dataio_xfer(sc, XFERDATAIN); + break; + case PH_COMMAND: + trm_command_phase1(sc); + break; + case PH_STATUS: + trm_status_phase1(sc); + break; + case PH_MSG_OUT: + trm_msgout_phase1(sc); + break; + case PH_MSG_IN: + trm_msgin_phase1(sc); + break; + case PH_BUS_FREE: + break; + default: + printf("%s: unexpected phase in trm_intr() phase1\n", + sc->sc_dev.dv_xname); + break; + } - /* - * call trm_scsi_phase1[]... "phase entry" handle every - * phase do transfer - */ - state_v = (void *)trm_scsi_phase1[phase]; - state_v(sc, srb, &stat); return (1); } return (0); } static void -trm_msgout_phase0(sc, srb, pstat) +trm_msgout_phase1(sc) struct trm_softc *sc; - struct trm_srb *srb; - int *pstat; -{ - - if (srb->state & (SRB_UNEXPECT_RESEL | SRB_ABORT_SENT)) - *pstat = PH_BUS_FREE; /* .. initial phase */ -} - -static void -trm_msgout_phase1(sc, srb, pstat) - struct trm_softc *sc; - struct trm_srb *srb; - int *pstat; { bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; - struct trm_dcb *dcb; + struct trm_srb *srb; + struct scsipi_periph *periph; + struct trm_tinfo *ti; bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_CLRFIFO); - dcb = sc->sc_actdcb; - if ((srb->state & SRB_MSGOUT) == 0) { - if (srb->msgcnt > 0) { - bus_space_write_multi_1(iot, ioh, TRM_SCSI_FIFO, - srb->msgout, srb->msgcnt); - srb->msgcnt = 0; - if ((dcb->flag & ABORT_DEV_) && - (srb->msgout[0] == MSG_ABORT)) - srb->state = SRB_ABORT_SENT; - } else { - if ((srb->cmd[0] == INQUIRY) || - (srb->cmd[0] == REQUEST_SENSE)) - if (dcb->mode & SYNC_NEGO_ENABLE) - goto mop1; - bus_space_write_1(iot, ioh, TRM_SCSI_FIFO, MSG_ABORT); - } - } else { -mop1: /* message out phase */ - if ((srb->state & SRB_DO_WIDE_NEGO) == 0 && - (dcb->mode & WIDE_NEGO_ENABLE)) { - /* - * WIDE DATA TRANSFER REQUEST code (03h) - */ - dcb->mode &= ~(SYNC_NEGO_DONE | EN_ATN_STOP); - bus_space_write_1(iot, ioh, TRM_SCSI_FIFO, - dcb->idmsg & ~MSG_IDENTIFY_DISCFLAG); - bus_space_write_1(iot, ioh, TRM_SCSI_FIFO, - MSG_EXTENDED); /* (01h) */ + srb = sc->sc_actsrb; - /* Message length (02h) */ - bus_space_write_1(iot, ioh, TRM_SCSI_FIFO, - MSG_EXT_WDTR_LEN); + /* message out phase */ + if (srb != NULL) { + periph = srb->xs->xs_periph; + ti = &sc->sc_tinfo[periph->periph_target]; - /* wide data xfer (03h) */ - bus_space_write_1(iot, ioh, TRM_SCSI_FIFO, - MSG_EXT_WDTR); + if ((ti->flag & WIDE_NEGO_DOING) == 0 && + (ti->flag & WIDE_NEGO_ENABLE)) { + /* send WDTR */ + ti->flag &= ~SYNC_NEGO_DONE; - /* width: 0(8bit), 1(16bit) ,2(32bit) */ - bus_space_write_1(iot, ioh, TRM_SCSI_FIFO, - MSG_EXT_WDTR_BUS_16_BIT); + sc->sc_msgbuf[0] = MSG_IDENTIFY(periph->periph_lun, 0); + sc->sc_msgbuf[1] = MSG_EXTENDED; + sc->sc_msgbuf[2] = MSG_EXT_WDTR_LEN; + sc->sc_msgbuf[3] = MSG_EXT_WDTR; + sc->sc_msgbuf[4] = MSG_EXT_WDTR_BUS_16_BIT; + sc->sc_msgcnt = 5; - srb->state |= SRB_DO_WIDE_NEGO; - } else if ((srb->state & SRB_DO_SYNC_NEGO) == 0 && - (dcb->mode & SYNC_NEGO_ENABLE)) { - /* - * SYNCHRONOUS DATA TRANSFER REQUEST code (01h) - */ - if ((dcb->mode & WIDE_NEGO_DONE) == 0) - bus_space_write_1(iot, ioh, TRM_SCSI_FIFO, - dcb->idmsg & ~MSG_IDENTIFY_DISCFLAG); + ti->flag |= WIDE_NEGO_DOING; + } else if ((ti->flag & SYNC_NEGO_DOING) == 0 && + (ti->flag & SYNC_NEGO_ENABLE)) { + /* send SDTR */ + int cnt = 0; - bus_space_write_1(iot, ioh, TRM_SCSI_FIFO, - MSG_EXTENDED); /* (01h) */ + if ((ti->flag & WIDE_NEGO_DONE) == 0) + sc->sc_msgbuf[cnt++] = + MSG_IDENTIFY(periph->periph_lun, 0); - /* Message length (03h) */ - bus_space_write_1(iot, ioh, TRM_SCSI_FIFO, - MSG_EXT_SDTR_LEN); - - /* SYNCHRONOUS DATA TRANSFER REQUEST code (01h) */ - bus_space_write_1(iot, ioh, TRM_SCSI_FIFO, - MSG_EXT_SDTR); - - /* Transfer peeriod factor */ - bus_space_write_1(iot, ioh, TRM_SCSI_FIFO, dcb->period); - - /* REQ/ACK offset */ - bus_space_write_1(iot, ioh, TRM_SCSI_FIFO, - SYNC_NEGO_OFFSET); - srb->state |= SRB_DO_SYNC_NEGO; + sc->sc_msgbuf[cnt++] = MSG_EXTENDED; + sc->sc_msgbuf[cnt++] = MSG_EXT_SDTR_LEN; + sc->sc_msgbuf[cnt++] = MSG_EXT_SDTR; + sc->sc_msgbuf[cnt++] = ti->period; + sc->sc_msgbuf[cnt++] = TRM_MAX_OFFSET; + sc->sc_msgcnt = cnt; + ti->flag |= SYNC_NEGO_DOING; } } + if (sc->sc_msgcnt == 0) { + sc->sc_msgbuf[0] = MSG_ABORT; + sc->sc_msgcnt = 1; + sc->sc_state = TRM_ABORT_SENT; + } + + DPRINTF(("msgout: cnt = %d, ", sc->sc_msgcnt)); + DPRINTF(("msgbuf = %02x %02x %02x %02x %02x %02x\n", + sc->sc_msgbuf[0], sc->sc_msgbuf[1], sc->sc_msgbuf[2], + sc->sc_msgbuf[3], sc->sc_msgbuf[4], sc->sc_msgbuf[5])); + + bus_space_write_multi_1(iot, ioh, TRM_SCSI_FIFO, + sc->sc_msgbuf, sc->sc_msgcnt); + sc->sc_msgcnt = 0; + memset(sc->sc_msgbuf, 0, sizeof(sc->sc_msgbuf)); + /* it's important for atn stop */ bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_DATALATCH); @@ -1231,27 +1306,23 @@ mop1: /* message out phase */ } static void -trm_command_phase0(sc, srb, pstat) +trm_command_phase1(sc) struct trm_softc *sc; - struct trm_srb *srb; - int *pstat; -{ - -} - -static void -trm_command_phase1(sc, srb, pstat) - struct trm_softc *sc; - struct trm_srb *srb; - int *pstat; { bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; + struct trm_srb *srb; + + srb = sc->sc_actsrb; + if (srb == NULL) { + DPRINTF(("trm_command_phase1: no active srb\n")); + return; + } bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_CLRATN | DO_CLRFIFO); bus_space_write_multi_1(iot, ioh, TRM_SCSI_FIFO, srb->cmd, srb->cmdlen); - srb->state = SRB_COMMAND; + sc->sc_state = TRM_COMMAND; /* it's important for atn stop */ bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_DATALATCH); @@ -1262,228 +1333,225 @@ trm_command_phase1(sc, srb, pstat) } static void -trm_dataout_phase0(sc, srb, pstat) +trm_dataout_phase0(sc, stat) struct trm_softc *sc; - struct trm_srb *srb; - int *pstat; + int stat; { bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; - struct trm_dcb *dcb; + struct trm_srb *srb; + struct scsipi_periph *periph; + struct trm_tinfo *ti; struct trm_sg_entry *sg; int sgindex; u_int32_t xferlen, leftcnt = 0; - dcb = srb->dcb; + if (sc->sc_state == TRM_XFERPAD) + return; - if ((srb->state & SRB_XFERPAD) == 0) { - if (*pstat & PARITYERROR) - srb->srbstat |= PARITY_ERROR; + srb = sc->sc_actsrb; + if (srb == NULL) { + DPRINTF(("trm_dataout_phase0: no active srb\n")); + return; + } + periph = srb->xs->xs_periph; + ti = &sc->sc_tinfo[periph->periph_target]; - if ((*pstat & SCSIXFERDONE) == 0) { - /* - * when data transfer from DMA FIFO to SCSI FIFO - * if there was some data left in SCSI FIFO - */ - leftcnt = bus_space_read_1(iot, ioh, TRM_SCSI_FIFOCNT) & - SCSI_FIFOCNT_MASK; - if (dcb->synctl & WIDE_SYNC) - /* - * if WIDE scsi SCSI FIFOCNT unit is word - * so need to * 2 - */ - leftcnt <<= 1; - } + if ((stat & PARITYERROR) != 0) + srb->flag |= PARITY_ERROR; + + if ((stat & SCSIXFERDONE) == 0) { /* - * caculate all the residue data that not yet tranfered - * SCSI transfer counter + left in SCSI FIFO data - * - * .....TRM_SCSI_XCNT (24bits) - * The counter always decrement by one for every SCSI - * byte transfer. - * .....TRM_SCSI_FIFOCNT ( 5bits) - * The counter is SCSI FIFO offset counter + * when data transfer from DMA FIFO to SCSI FIFO + * if there was some data left in SCSI FIFO */ - leftcnt += bus_space_read_4(iot, ioh, TRM_SCSI_XCNT); - if (leftcnt == 1) { - leftcnt = 0; - bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, - DO_CLRFIFO); - } - if ((leftcnt == 0) || (*pstat & SCSIXFERCNT_2_ZERO)) { - while ((bus_space_read_1(iot, ioh, TRM_DMA_STATUS) & - DMAXFERCOMP) == 0) - ; - - srb->buflen = 0; - } else { /* Update SG list */ + leftcnt = bus_space_read_1(iot, ioh, TRM_SCSI_FIFOCNT) & + SCSI_FIFOCNT_MASK; + if (ti->synctl & WIDE_SYNC) /* - * if transfer not yet complete - * there were some data residue in SCSI FIFO or - * SCSI transfer counter not empty + * if WIDE scsi SCSI FIFOCNT unit is word + * so need to * 2 */ - if (srb->buflen != leftcnt) { - /* data that had transferred length */ - xferlen = srb->buflen - leftcnt; + leftcnt <<= 1; + } + /* + * caculate all the residue data that not yet tranfered + * SCSI transfer counter + left in SCSI FIFO data + * + * .....TRM_SCSI_XCNT (24bits) + * The counter always decrement by one for every SCSI + * byte transfer. + * .....TRM_SCSI_FIFOCNT ( 5bits) + * The counter is SCSI FIFO offset counter + */ + leftcnt += bus_space_read_4(iot, ioh, TRM_SCSI_XCNT); + if (leftcnt == 1) { + leftcnt = 0; + bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_CLRFIFO); + } + if ((leftcnt == 0) || (stat & SCSIXFERCNT_2_ZERO)) { + while ((bus_space_read_1(iot, ioh, TRM_DMA_STATUS) & + DMAXFERCOMP) == 0) + ; /* XXX needs timeout */ - /* next time to be transferred length */ - srb->buflen = leftcnt; + srb->buflen = 0; + } else { + /* Update SG list */ + /* + * if transfer not yet complete + * there were some data residue in SCSI FIFO or + * SCSI transfer counter not empty + */ + if (srb->buflen != leftcnt) { + /* data that had transferred length */ + xferlen = srb->buflen - leftcnt; + + /* next time to be transferred length */ + srb->buflen = leftcnt; + + /* + * parsing from last time disconnect sgindex + */ + sg = srb->sgentry + srb->sgindex; + for (sgindex = srb->sgindex; + sgindex < srb->sgcnt; + sgindex++, sg++) { /* - * parsing from last time disconnect sgindex + * find last time which SG transfer + * be disconnect */ - sg = srb->sgentry + srb->sgindex; - for (sgindex = srb->sgindex; - sgindex < srb->sgcnt; - sgindex++, sg++) { + if (xferlen >= le32toh(sg->length)) + xferlen -= le32toh(sg->length); + else { /* - * find last time which SG transfer - * be disconnect + * update last time + * disconnected SG list */ - if (xferlen >= le32toh(sg->length)) - xferlen -= le32toh(sg->length); - else { - /* - * update last time - * disconnected SG list - */ - /* residue data length */ - sg->length = htole32( - le32toh(sg->length) - - xferlen); - /* residue data pointer */ - sg->address = htole32( - le32toh(sg->address) - + xferlen); - srb->sgindex = sgindex; - break; - } + /* residue data length */ + sg->length = + htole32(le32toh(sg->length) + - xferlen); + /* residue data pointer */ + sg->address = + htole32(le32toh(sg->address) + + xferlen); + srb->sgindex = sgindex; + break; } - bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, - srb->sgoffset, TRM_SG_SIZE, - BUS_DMASYNC_PREWRITE); } + bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, + srb->sgoffset, TRM_SG_SIZE, BUS_DMASYNC_PREWRITE); } } bus_space_write_1(iot, ioh, TRM_DMA_CONTROL, STOPDMAXFER); } static void -trm_dataout_phase1(sc, srb, pstat) +trm_datain_phase0(sc, stat) struct trm_softc *sc; - struct trm_srb *srb; - int *pstat; -{ - - /* - * do prepare befor transfer when data out phase - */ - trm_dataio_xfer(sc, srb, XFERDATAOUT); -} - -static void -trm_datain_phase0(sc, srb, pstat) - struct trm_softc *sc; - struct trm_srb *srb; - int *pstat; + int stat; { bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; + struct trm_srb *srb; struct trm_sg_entry *sg; int sgindex; u_int32_t xferlen, leftcnt = 0; - if ((srb->state & SRB_XFERPAD) == 0) { - if (*pstat & PARITYERROR) - srb->srbstat |= PARITY_ERROR; + if (sc->sc_state == TRM_XFERPAD) + return; - leftcnt += bus_space_read_4(iot, ioh, TRM_SCSI_XCNT); - if ((leftcnt == 0) || (*pstat & SCSIXFERCNT_2_ZERO)) { - while ((bus_space_read_1(iot, ioh, TRM_DMA_STATUS) & - DMAXFERCOMP) == 0) - ; + srb = sc->sc_actsrb; + if (srb == NULL) { + DPRINTF(("trm_datain_phase0: no active srb\n")); + return; + } - srb->buflen = 0; - } else { /* phase changed */ + if (stat & PARITYERROR) + srb->flag |= PARITY_ERROR; + + leftcnt += bus_space_read_4(iot, ioh, TRM_SCSI_XCNT); + if ((leftcnt == 0) || (stat & SCSIXFERCNT_2_ZERO)) { + while ((bus_space_read_1(iot, ioh, TRM_DMA_STATUS) & + DMAXFERCOMP) == 0) + ; /* XXX needs timeout */ + + srb->buflen = 0; + } else { /* phase changed */ + /* + * parsing the case: + * when a transfer not yet complete + * but be disconnected by uper layer + * if transfer not yet complete + * there were some data residue in SCSI FIFO or + * SCSI transfer counter not empty + */ + if (srb->buflen != leftcnt) { /* - * parsing the case: - * when a transfer not yet complete - * but be disconnected by uper layer - * if transfer not yet complete - * there were some data residue in SCSI FIFO or - * SCSI transfer counter not empty + * data that had transferred length */ - if (srb->buflen != leftcnt) { - /* - * data that had transferred length - */ - xferlen = srb->buflen - leftcnt; + xferlen = srb->buflen - leftcnt; - /* - * next time to be transferred length - */ - srb->buflen = leftcnt; + /* + * next time to be transferred length + */ + srb->buflen = leftcnt; + /* + * parsing from last time disconnect sgindex + */ + sg = srb->sgentry + srb->sgindex; + for (sgindex = srb->sgindex; + sgindex < srb->sgcnt; + sgindex++, sg++) { /* - * parsing from last time disconnect sgindex + * find last time which SG transfer + * be disconnect */ - sg = srb->sgentry + srb->sgindex; - for (sgindex = srb->sgindex; - sgindex < srb->sgcnt; - sgindex++, sg++) { + if (xferlen >= le32toh(sg->length)) + xferlen -= le32toh(sg->length); + else { /* - * find last time which SG transfer - * be disconnect + * update last time + * disconnected SG list */ - if (xferlen >= le32toh(sg->length)) - xferlen -= le32toh(sg->length); - else { - /* - * update last time - * disconnected SG list - */ - /* residue data length */ - sg->length = htole32( - le32toh(sg->length) - - xferlen); - /* residue data pointer */ - sg->address = htole32( - le32toh(sg->address) - + xferlen); - srb->sgindex = sgindex; - break; - } + /* residue data length */ + sg->length = + htole32(le32toh(sg->length) + - xferlen); + /* residue data pointer */ + sg->address = + htole32(le32toh(sg->address) + + xferlen); + srb->sgindex = sgindex; + break; } - bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, - srb->sgoffset, TRM_SG_SIZE, - BUS_DMASYNC_PREWRITE); } + bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, + srb->sgoffset, TRM_SG_SIZE, BUS_DMASYNC_PREWRITE); } } } static void -trm_datain_phase1(sc, srb, pstat) +trm_dataio_xfer(sc, iodir) struct trm_softc *sc; - struct trm_srb *srb; - int *pstat; -{ - - /* - * do prepare befor transfer when data in phase - */ - trm_dataio_xfer(sc, srb, XFERDATAIN); -} - -static void -trm_dataio_xfer(sc, srb, iodir) - struct trm_softc *sc; - struct trm_srb *srb; int iodir; { bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; - struct trm_dcb *dcb = srb->dcb; + struct trm_srb *srb; + struct scsipi_periph *periph; + struct trm_tinfo *ti; + + srb = sc->sc_actsrb; + if (srb == NULL) { + DPRINTF(("trm_dataio_xfer: no active srb\n")); + return; + } + periph = srb->xs->xs_periph; + ti = &sc->sc_tinfo[periph->periph_target]; if (srb->sgindex < srb->sgcnt) { if (srb->buflen > 0) { @@ -1491,7 +1559,7 @@ trm_dataio_xfer(sc, srb, iodir) * load what physical address of Scatter/Gather * list table want to be transfer */ - srb->state = SRB_DATA_XFER; + sc->sc_state = TRM_DATA_XFER; bus_space_write_4(iot, ioh, TRM_DMA_XHIGHADDR, 0); bus_space_write_4(iot, ioh, TRM_DMA_XLOWADDR, srb->sgaddr + @@ -1526,17 +1594,16 @@ trm_dataio_xfer(sc, srb, iodir) } else { /* xfer pad */ if (srb->sgcnt) { srb->hastat = H_OVER_UNDER_RUN; - srb->srbstat |= OVER_RUN; } bus_space_write_4(iot, ioh, TRM_SCSI_XCNT, - (dcb->synctl & WIDE_SYNC) ? 2 : 1); + (ti->synctl & WIDE_SYNC) ? 2 : 1); if (iodir == XFERDATAOUT) bus_space_write_2(iot, ioh, TRM_SCSI_FIFO, 0); else bus_space_read_2(iot, ioh, TRM_SCSI_FIFO); - srb->state |= SRB_XFERPAD; + sc->sc_state = TRM_XFERPAD; /* it's important for atn stop */ bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_DATALATCH); @@ -1552,31 +1619,32 @@ trm_dataio_xfer(sc, srb, iodir) } static void -trm_status_phase0(sc, srb, pstat) +trm_status_phase0(sc) struct trm_softc *sc; - struct trm_srb *srb; - int *pstat; { bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; + struct trm_srb *srb; + srb = sc->sc_actsrb; + if (srb == NULL) { + DPRINTF(("trm_status_phase0: no active srb\n")); + return; + } srb->tastat = bus_space_read_1(iot, ioh, TRM_SCSI_FIFO); - srb->state = SRB_COMPLETED; - *pstat = PH_BUS_FREE; /* .. initial phase */ + sc->sc_state = TRM_COMPLETED; /* it's important for atn stop */ bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_DATALATCH); /* - * SCSI cammand + * SCSI command */ bus_space_write_1(iot, ioh, TRM_SCSI_COMMAND, SCMD_MSGACCEPT); } static void -trm_status_phase1(sc, srb, pstat) +trm_status_phase1(sc) struct trm_softc *sc; - struct trm_srb *srb; - int *pstat; { bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; @@ -1598,7 +1666,7 @@ trm_status_phase1(sc, srb, pstat) bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_CLRFIFO); } - srb->state = SRB_STATUS; + sc->sc_state = TRM_STATUS; /* it's important for atn stop */ bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_DATALATCH); @@ -1609,100 +1677,115 @@ trm_status_phase1(sc, srb, pstat) } static void -trm_msgin_phase0(sc, srb, pstat) +trm_msgin_phase0(sc) struct trm_softc *sc; - struct trm_srb *srb; - int *pstat; { bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; - struct trm_dcb *dcb = sc->sc_actdcb; - struct trm_srb *tempsrb; - int syncxfer, tagid, index; + struct trm_srb *srb; + struct scsipi_periph *periph; + struct trm_tinfo *ti; + int index; u_int8_t msgin_code; msgin_code = bus_space_read_1(iot, ioh, TRM_SCSI_FIFO); - if ((srb->state & SRB_EXTEND_MSGIN) == 0) { - if (msgin_code == MSG_DISCONNECT) { - srb->state = SRB_DISCONNECT; - goto min6; - } else if (msgin_code == MSG_SAVEDATAPOINTER) { - goto min6; - } else if ((msgin_code == MSG_EXTENDED) || - ((msgin_code >= MSG_SIMPLE_Q_TAG) && - (msgin_code <= MSG_ORDERED_Q_TAG))) { - srb->state |= SRB_EXTEND_MSGIN; + if (sc->sc_state != TRM_EXTEND_MSGIN) { + DPRINTF(("msgin: code = %02x\n", msgin_code)); + switch (msgin_code) { + case MSG_DISCONNECT: + sc->sc_state = TRM_DISCONNECTED; + break; + + case MSG_SAVEDATAPOINTER: + break; + + case MSG_EXTENDED: + case MSG_SIMPLE_Q_TAG: + case MSG_HEAD_OF_Q_TAG: + case MSG_ORDERED_Q_TAG: + sc->sc_state = TRM_EXTEND_MSGIN; /* extended message (01h) */ - srb->msgin[0] = msgin_code; + sc->sc_msgbuf[0] = msgin_code; - srb->msgcnt = 1; + sc->sc_msgcnt = 1; /* extended message length (n) */ - srb->msg = &srb->msgin[1]; + sc->sc_msg = &sc->sc_msgbuf[1]; - goto min6; - } else if (msgin_code == MSG_MESSAGE_REJECT) { + break; + case MSG_MESSAGE_REJECT: /* Reject message */ - /* do wide nego reject */ - if (dcb->mode & WIDE_NEGO_ENABLE) { - dcb = srb->dcb; - dcb->mode |= WIDE_NEGO_DONE; - dcb->mode &= ~(SYNC_NEGO_DONE | EN_ATN_STOP | - WIDE_NEGO_ENABLE); - srb->state &= ~(SRB_DO_WIDE_NEGO | SRB_MSGIN); - if ((dcb->mode & SYNC_NEGO_ENABLE) && - (dcb->mode & SYNC_NEGO_DONE) == 0) { + srb = sc->sc_actsrb; + if (srb == NULL) { + DPRINTF(("trm_msgin_phase0: " + " message reject without actsrb\n")); + break; + } + periph = srb->xs->xs_periph; + ti = &sc->sc_tinfo[periph->periph_target]; + + if (ti->flag & WIDE_NEGO_ENABLE) { + /* do wide nego reject */ + ti->flag |= WIDE_NEGO_DONE; + ti->flag &= + ~(SYNC_NEGO_DONE | WIDE_NEGO_ENABLE); + if ((ti->flag & SYNC_NEGO_ENABLE) && + (ti->flag & SYNC_NEGO_DONE) == 0) { /* Set ATN, in case ATN was clear */ - srb->state |= SRB_MSGOUT; + sc->sc_state = TRM_MSGOUT; bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_SETATN); } else /* Clear ATN */ bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_CLRATN); - } else if (dcb->mode & SYNC_NEGO_ENABLE) { + } else if (ti->flag & SYNC_NEGO_ENABLE) { /* do sync nego reject */ bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_CLRATN); - if (srb->state & SRB_DO_SYNC_NEGO) { - dcb = srb->dcb; - dcb->mode &= ~(SYNC_NEGO_ENABLE | + if (ti->flag & SYNC_NEGO_DOING) { + ti->flag &=~(SYNC_NEGO_ENABLE | SYNC_NEGO_DONE); - dcb->synctl = 0; - dcb->offset = 0; - goto re_prog; + ti->synctl = 0; + ti->offset = 0; + bus_space_write_1(iot, ioh, + TRM_SCSI_SYNC, ti->synctl); + bus_space_write_1(iot, ioh, + TRM_SCSI_OFFSET, ti->offset); } } - goto min6; - } else if (msgin_code == MSG_IGN_WIDE_RESIDUE) { + break; + + case MSG_IGN_WIDE_RESIDUE: bus_space_write_4(iot, ioh, TRM_SCSI_XCNT, 1); bus_space_read_1(iot, ioh, TRM_SCSI_FIFO); - goto min6; - } else { + break; + + default: /* * Restore data pointer message * Save data pointer message * Completion message * NOP message */ - goto min6; + break; } } else { /* - * when extend message in:srb->state = SRB_EXTEND_MSGIN + * when extend message in: sc->sc_state = TRM_EXTEND_MSGIN * Parsing incomming extented messages */ - *srb->msg = msgin_code; - srb->msgcnt++; - srb->msg++; -#ifdef TRM_DEBUG - printf("srb->msgin[0]=%2x\n", srb->msgin[0]); - printf("srb->msgin[1]=%2x\n", srb->msgin[1]); - printf("srb->msgin[2]=%2x\n", srb->msgin[2]); - printf("srb->msgin[3]=%2x\n", srb->msgin[3]); - printf("srb->msgin[4]=%2x\n", srb->msgin[4]); -#endif - if ((srb->msgin[0] >= MSG_SIMPLE_Q_TAG) && - (srb->msgin[0] <= MSG_ORDERED_Q_TAG)) { + *sc->sc_msg++ = msgin_code; + sc->sc_msgcnt++; + + DPRINTF(("extended_msgin: cnt = %d, ", sc->sc_msgcnt)); + DPRINTF(("msgbuf = %02x %02x %02x %02x %02x %02x\n", + sc->sc_msgbuf[0], sc->sc_msgbuf[1], sc->sc_msgbuf[2], + sc->sc_msgbuf[3], sc->sc_msgbuf[4], sc->sc_msgbuf[5])); + + switch (sc->sc_msgbuf[0]) { + case MSG_SIMPLE_Q_TAG: + case MSG_HEAD_OF_Q_TAG: + case MSG_ORDERED_Q_TAG: /* * is QUEUE tag message : * @@ -1713,197 +1796,177 @@ trm_msgin_phase0(sc, srb, pstat) * byte 1: * Queue tag (00h - FFh) */ - if (srb->msgcnt == 2) { - srb->state = 0; - tagid = srb->msgin[1]; - srb = dcb->gosrb; - tempsrb = dcb->last_gosrb; - if (srb) { - for (;;) { - if (srb->tagnum != tagid) { - if (srb == tempsrb) - goto mingx0; + if (sc->sc_msgcnt == 2 && sc->sc_actsrb == NULL) { + /* XXX XXX XXX */ + struct trm_linfo *li; + int tagid; - srb = srb->next; - } else - break; - } - if (dcb->flag & ABORT_DEV_) { - srb->state = SRB_ABORT_SENT; - srb->msgout[0] = MSG_ABORT; - trm_msgout_abort(sc, srb); - } - if ((srb->state & SRB_DISCONNECT) == 0) - goto mingx0; - - dcb->actsrb = srb; - srb->state = SRB_DATA_XFER; + sc->sc_flag &= ~WAIT_TAGMSG; + tagid = sc->sc_msgbuf[1]; + ti = &sc->sc_tinfo[sc->resel_target]; + li = ti->linfo[sc->resel_lun]; + srb = li->queued[tagid]; + if (srb != NULL) { + sc->sc_actsrb = srb; + sc->sc_state = TRM_DATA_XFER; + break; } else { - mingx0: - srb = &sc->sc_tempsrb; - srb->state = SRB_UNEXPECT_RESEL; - dcb->actsrb = srb; - srb->msgout[0] = MSG_ABORT_TAG; - trm_msgout_abort(sc, srb); + printf("%s: invalid tag id\n", + sc->sc_dev.dv_xname); } - } - } else if ((srb->msgin[0] == MSG_EXTENDED) && - (srb->msgin[2] == MSG_EXT_WDTR) && - (srb->msgcnt == 4)) { - /* - * is Wide data xfer Extended message : - * ====================================== - * WIDE DATA TRANSFER REQUEST - * ====================================== - * byte 0 : Extended message (01h) - * byte 1 : Extended message length (02h) - * byte 2 : WIDE DATA TRANSFER code (03h) - * byte 3 : Transfer width exponent - */ - dcb = srb->dcb; - srb->state &= ~(SRB_EXTEND_MSGIN | SRB_DO_WIDE_NEGO); - if ((srb->msgin[1] != MSG_EXT_WDTR_LEN)) { - /* Length is wrong, reject it */ - dcb->mode &= - ~(WIDE_NEGO_ENABLE | WIDE_NEGO_DONE); - srb->msgcnt = 1; - srb->msgin[0] = MSG_MESSAGE_REJECT; + + sc->sc_state = TRM_UNEXPECT_RESEL; + sc->sc_msgbuf[0] = MSG_ABORT_TAG; + sc->sc_msgcnt = 1; bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_SETATN); - goto min6; + } else + sc->sc_state = TRM_IDLE; + break; + + case MSG_EXTENDED: + srb = sc->sc_actsrb; + if (srb == NULL) { + DPRINTF(("trm_msgin_phase0: " + "extended message without actsrb\n")); + break; } - if (dcb->mode & WIDE_NEGO_ENABLE) { - /* Do wide negoniation */ - if (srb->msgin[3] > MSG_EXT_WDTR_BUS_32_BIT) { - /* reject_msg: */ - dcb->mode &= ~(WIDE_NEGO_ENABLE | + periph = srb->xs->xs_periph; + ti = &sc->sc_tinfo[periph->periph_target]; + + if (sc->sc_msgbuf[2] == MSG_EXT_WDTR && + sc->sc_msgcnt == 4) { + /* + * is Wide data xfer Extended message : + * ====================================== + * WIDE DATA TRANSFER REQUEST + * ====================================== + * byte 0 : Extended message (01h) + * byte 1 : Extended message length (02h) + * byte 2 : WIDE DATA TRANSFER code (03h) + * byte 3 : Transfer width exponent + */ + if (sc->sc_msgbuf[1] != MSG_EXT_WDTR_LEN) { + /* Length is wrong, reject it */ + ti->flag &= ~(WIDE_NEGO_ENABLE | WIDE_NEGO_DONE); - srb->msgcnt = 1; - srb->msgin[0] = MSG_MESSAGE_REJECT; + sc->sc_state = TRM_MSGOUT; + sc->sc_msgbuf[0] = MSG_MESSAGE_REJECT; + sc->sc_msgcnt = 1; bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_SETATN); - goto min6; + break; } - if (srb->msgin[3] == MSG_EXT_WDTR_BUS_32_BIT) - /* do 16 bits */ - srb->msgin[3] = MSG_EXT_WDTR_BUS_16_BIT; - else { - if ((dcb->mode & WIDE_NEGO_DONE) == 0) { - srb->state &= - ~(SRB_DO_WIDE_NEGO | - SRB_MSGIN); - dcb->mode |= WIDE_NEGO_DONE; - dcb->mode &= - ~(SYNC_NEGO_DONE | - EN_ATN_STOP | - WIDE_NEGO_ENABLE); - if (srb->msgin[3] != - MSG_EXT_WDTR_BUS_8_BIT) - /* is Wide data xfer */ - dcb->synctl |= - WIDE_SYNC; - } - } - } else - srb->msgin[3] = MSG_EXT_WDTR_BUS_8_BIT; - srb->state |= SRB_MSGOUT; - bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, - DO_SETATN); - goto min6; - } else if ((srb->msgin[0] == MSG_EXTENDED) && - (srb->msgin[2] == MSG_EXT_SDTR) && - (srb->msgcnt == 5)) { - /* - * is 8bit transfer Extended message : - * ================================= - * SYNCHRONOUS DATA TRANSFER REQUEST - * ================================= - * byte 0 : Extended message (01h) - * byte 1 : Extended message length (03) - * byte 2 : SYNCHRONOUS DATA TRANSFER code (01h) - * byte 3 : Transfer period factor - * byte 4 : REQ/ACK offset - */ - srb->state &= ~(SRB_EXTEND_MSGIN | SRB_DO_SYNC_NEGO); - if (srb->msgin[1] != MSG_EXT_SDTR_LEN) { - /* reject_msg: */ - srb->msgcnt = 1; - srb->msgin[0] = MSG_MESSAGE_REJECT; + if ((ti->flag & WIDE_NEGO_ENABLE) == 0) + sc->sc_msgbuf[3] = + MSG_EXT_WDTR_BUS_8_BIT; + + if (sc->sc_msgbuf[3] > + MSG_EXT_WDTR_BUS_32_BIT) { + /* reject_msg: */ + ti->flag &= ~(WIDE_NEGO_ENABLE | + WIDE_NEGO_DONE); + sc->sc_state = TRM_MSGOUT; + sc->sc_msgbuf[0] = MSG_MESSAGE_REJECT; + sc->sc_msgcnt = 1; + bus_space_write_2(iot, ioh, + TRM_SCSI_CONTROL, DO_SETATN); + break; + } + if (sc->sc_msgbuf[3] == MSG_EXT_WDTR_BUS_32_BIT) + /* do 16 bits */ + sc->sc_msgbuf[3] = + MSG_EXT_WDTR_BUS_16_BIT; + if ((ti->flag & WIDE_NEGO_DONE) == 0) { + ti->flag |= WIDE_NEGO_DONE; + ti->flag &= ~(SYNC_NEGO_DONE | + WIDE_NEGO_ENABLE); + if (sc->sc_msgbuf[3] != + MSG_EXT_WDTR_BUS_8_BIT) + /* is Wide data xfer */ + ti->synctl |= WIDE_SYNC; + trm_update_xfer_mode(sc, + periph->periph_target); + } + + sc->sc_state = TRM_MSGOUT; bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_SETATN); - } else if (srb->msgin[3] == 0 || srb->msgin[4] == 0) { - /* set async */ - dcb = srb->dcb; - /* disable sync & sync nego */ - dcb->mode &= - ~(SYNC_NEGO_ENABLE | SYNC_NEGO_DONE); - dcb->synctl = 0; - dcb->offset = 0; - if (((dcb->flag & SHOW_MESSAGE_) == 0) && - (dcb->lun == 0)) { - printf("%s: target %d, Sync period=0 " - "or Sync offset=0 to be " - "asynchronous transfer\n", - sc->sc_dev.dv_xname, dcb->id); - dcb->flag |= SHOW_MESSAGE_; - } - goto re_prog; - } else { /* set sync */ - dcb = srb->dcb; - dcb->mode |= SYNC_NEGO_ENABLE | SYNC_NEGO_DONE; + break; - /* Transfer period factor */ - dcb->period = srb->msgin[3]; - - /* REQ/ACK offset */ - dcb->offset = srb->msgin[4]; - for (index = 0; index < 7; index++) - if (srb->msgin[3] <= - trm_clock_period[index]) - break; - - dcb->synctl |= (index | ALT_SYNC); + } else if (sc->sc_msgbuf[2] == MSG_EXT_SDTR && + sc->sc_msgcnt == 5) { /* - * show negotiation message + * is 8bit transfer Extended message : + * ================================= + * SYNCHRONOUS DATA TRANSFER REQUEST + * ================================= + * byte 0 : Extended message (01h) + * byte 1 : Extended message length (03) + * byte 2 : SYNC DATA TRANSFER code (01h) + * byte 3 : Transfer period factor + * byte 4 : REQ/ACK offset */ - if (((dcb->flag & SHOW_MESSAGE_) == 0) && - (dcb->lun == 0)) { - syncxfer = 100000 / - (trm_clock_period[index] * 4); - if (dcb->synctl & WIDE_SYNC) { - printf("%s: target %d, " - "16bits Wide transfer\n", - sc->sc_dev.dv_xname, - dcb->id); - syncxfer = syncxfer * 2; - } else - printf("%s: target %d, " - "8bits Narrow transfer\n", - sc->sc_dev.dv_xname, - dcb->id); - - printf("%s: target %d, " - "Sync transfer %d.%01d MB/sec, " - "Offset %d\n", sc->sc_dev.dv_xname, - dcb->id, syncxfer / 100, - syncxfer % 100, dcb->offset); - dcb->flag |= SHOW_MESSAGE_; + if (sc->sc_msgbuf[1] != MSG_EXT_SDTR_LEN) { + /* reject_msg */ + sc->sc_state = TRM_MSGOUT; + sc->sc_msgbuf[0] = MSG_MESSAGE_REJECT; + sc->sc_msgcnt = 1; + bus_space_write_2(iot, ioh, + TRM_SCSI_CONTROL, DO_SETATN); + break; } - re_prog: - /* - * program SCSI control register - */ - bus_space_write_1(iot, ioh, TRM_SCSI_SYNC, - dcb->synctl); - bus_space_write_1(iot, ioh, TRM_SCSI_OFFSET, - dcb->offset); - trm_set_xfer_rate(sc, srb, dcb); + + if ((ti->flag & SYNC_NEGO_DONE) == 0) { + ti->flag &= + ~(SYNC_NEGO_ENABLE|SYNC_NEGO_DOING); + ti->flag |= SYNC_NEGO_DONE; + if (sc->sc_msgbuf[3] >= TRM_MAX_PERIOD) + sc->sc_msgbuf[3] = 0; + if (sc->sc_msgbuf[4] > TRM_MAX_OFFSET) + sc->sc_msgbuf[4] = + TRM_MAX_OFFSET; + + if (sc->sc_msgbuf[3] == 0 || + sc->sc_msgbuf[4] == 0) { + /* set async */ + ti->synctl = 0; + ti->offset = 0; + } else { + /* set sync */ + /* Transfer period factor */ + ti->period = sc->sc_msgbuf[3]; + /* REQ/ACK offset */ + ti->offset = sc->sc_msgbuf[4]; + for (index = 0; + index < NPERIOD; + index++) + if (ti->period <= + trm_clock_period[ + index]) + break; + + ti->synctl |= ALT_SYNC | index; + } + /* + * program SCSI control register + */ + bus_space_write_1(iot, ioh, + TRM_SCSI_SYNC, ti->synctl); + bus_space_write_1(iot, ioh, + TRM_SCSI_OFFSET, ti->offset); + trm_update_xfer_mode(sc, + periph->periph_target); + } + sc->sc_state = TRM_IDLE; } + break; + default: + break; } } -min6: - *pstat = PH_BUS_FREE; /* .. initial phase */ + /* it's important for atn stop */ bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_DATALATCH); @@ -1914,20 +1977,18 @@ min6: } static void -trm_msgin_phase1(sc, srb, pstat) +trm_msgin_phase1(sc) struct trm_softc *sc; - struct trm_srb *srb; - int *pstat; { bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_CLRFIFO); bus_space_write_4(iot, ioh, TRM_SCSI_XCNT, 1); - if ((srb->state & SRB_MSGIN) == 0) { - srb->state &= SRB_DISCONNECT; - srb->state |= SRB_MSGIN; + if (sc->sc_state != TRM_MSGIN && sc->sc_state != TRM_EXTEND_MSGIN) { + sc->sc_state = TRM_MSGIN; } + /* it's important for atn stop */ bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_DATALATCH); @@ -1937,135 +1998,88 @@ trm_msgin_phase1(sc, srb, pstat) bus_space_write_1(iot, ioh, TRM_SCSI_COMMAND, SCMD_FIFO_IN); } -static void -trm_nop0(sc, srb, pstat) - struct trm_softc *sc; - struct trm_srb *srb; - int *pstat; -{ - -} - -static void -trm_nop1(sc, srb, pstat) - struct trm_softc *sc; - struct trm_srb *srb; - int *pstat; -{ - -} - -static void -trm_set_xfer_rate(sc, srb, dcb) - struct trm_softc *sc; - struct trm_srb *srb; - struct trm_dcb *dcb; -{ - struct trm_dcb *tempdcb; - int i; - - /* - * set all lun device's (period, offset) - */ -#ifdef TRM_DEBUG - printf("trm_set_xfer_rate............\n"); -#endif - if ((dcb->idmsg & 0x07) == 0) { - if (sc->devscan_end == 0) - sc->cur_offset = dcb->offset; - else { - tempdcb = sc->sc_linkdcb; - for (i = 0; i < sc->devcnt; i++) { - /* - * different LUN but had same target ID - */ - if (tempdcb->id == dcb->id) { - tempdcb->synctl = dcb->synctl; - tempdcb->offset = dcb->offset; - tempdcb->mode = dcb->mode; - } - tempdcb = tempdcb->next; - } - } - } -} - static void trm_disconnect(sc) struct trm_softc *sc; { bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; - struct trm_dcb *dcb; - struct trm_srb *srb, *psrb; - int i, s; + struct trm_srb *srb; + int s; -#ifdef TRM_DEBUG - printf("trm_disconnect...............\n"); -#endif s = splbio(); - dcb = sc->sc_actdcb; - if (dcb == NULL) { + srb = sc->sc_actsrb; + DPRINTF(("trm_disconnect...............\n")); + + if (srb == NULL) { + DPRINTF(("trm_disconnect: no active srb\n")); DELAY(1000); /* 1 msec */ bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_CLRFIFO | DO_HWRESELECT); return; } - srb = dcb->actsrb; - sc->sc_actdcb = 0; - srb->phase = PH_BUS_FREE; /* SCSI bus free Phase */ + sc->sc_phase = PH_BUS_FREE; /* SCSI bus free Phase */ bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_CLRFIFO | DO_HWRESELECT); DELAY(100); - if (srb->state & SRB_UNEXPECT_RESEL) { - srb->state = 0; - trm_wait_srb(sc); - } else if (srb->state & SRB_ABORT_SENT) { - dcb->tagmask = 0; - dcb->flag &= ~ABORT_DEV_; - srb = dcb->gosrb; - for (i = 0; i < dcb->gosrb_cnt; i++) { - psrb = srb->next; - srb->next = sc->sc_freesrb; - sc->sc_freesrb = srb; - srb = psrb; - } - dcb->gosrb_cnt = 0; - dcb->gosrb = 0; - trm_wait_srb(sc); - } else { - if ((srb->state & (SRB_START_ | SRB_MSGOUT)) || - (srb->state & (SRB_DISCONNECT | SRB_COMPLETED)) == 0) { - /* Selection time out */ - if (sc->devscan_end) { - srb->state = SRB_READY; - trm_rewait_srb(dcb, srb); - } else { - srb->tastat = SCSI_SEL_TIMEOUT; - goto disc1; + + switch (sc->sc_state) { + case TRM_UNEXPECT_RESEL: + sc->sc_state = TRM_IDLE; + break; + + case TRM_ABORT_SENT: + goto finish; + + case TRM_START: + case TRM_MSGOUT: + { + /* Selection time out - discard all LUNs if empty */ + struct scsipi_periph *periph; + struct trm_tinfo *ti; + struct trm_linfo *li; + int lun; + + DPRINTF(("selection timeout\n")); + + srb->tastat = SCSI_SEL_TIMEOUT; /* XXX Ok? */ + + periph = srb->xs->xs_periph; + ti = &sc->sc_tinfo[periph->periph_target]; + for (lun = 0; lun < TRM_MAX_LUNS; lun++) { + li = ti->linfo[lun]; + if (li != NULL && + li->untagged == NULL && li->used == 0) { + ti->linfo[lun] = NULL; + free(li, M_DEVBUF); + } } - } else if (srb->state & SRB_DISCONNECT) { - /* - * SRB_DISCONNECT - */ - trm_wait_srb(sc); - } else if (srb->state & SRB_COMPLETED) { - disc1: - /* - * SRB_COMPLETED - */ - if (dcb->maxcmd > 1) { - /* free tag mask */ - dcb->tagmask &= ~(1 << srb->tagnum); - } - dcb->actsrb = 0; - srb->state = SRB_FREE; - trm_srb_done(sc, dcb, srb); } + goto finish; + + case TRM_DISCONNECTED: + sc->sc_actsrb = NULL; + sc->sc_state = TRM_IDLE; + goto sched; + + case TRM_COMPLETED: + goto finish; } + + out: splx(s); + return; + + finish: + sc->sc_state = TRM_IDLE; + trm_done(sc, srb); + goto out; + + sched: + trm_sched(sc); + goto out; } static void @@ -2074,70 +2088,71 @@ trm_reselect(sc) { bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; - struct trm_dcb *dcb; - struct trm_srb *srb; - int id, lun; + struct trm_tinfo *ti; + struct trm_linfo *li; + int target, lun; -#ifdef TRM_DEBUG - printf("trm_reselect.................\n"); -#endif - dcb = sc->sc_actdcb; - if (dcb != NULL) { /* Arbitration lost but Reselection win */ - srb = dcb->actsrb; - srb->state = SRB_READY; - trm_rewait_srb(dcb, srb); - } - /* Read Reselected Target Id and LUN */ - id = bus_space_read_1(iot, ioh, TRM_SCSI_TARGETID); - lun = bus_space_read_1(iot, ioh, TRM_SCSI_IDMSG) & 0x07; - dcb = sc->sc_linkdcb; - while (id != dcb->id && lun != dcb->lun) - /* get dcb of the reselect id */ - dcb = dcb->next; + DPRINTF(("trm_reselect.................\n")); - sc->sc_actdcb = dcb; - if (dcb->mode & EN_TAG_QUEUING) { - srb = &sc->sc_tempsrb; - dcb->actsrb = srb; + if (sc->sc_actsrb != NULL) { + /* arbitration lost but reselection win */ + sc->sc_state = TRM_READY; + target = sc->sc_actsrb->xs->xs_periph->periph_target; + ti = &sc->sc_tinfo[target]; } else { - srb = dcb->actsrb; - if (srb == NULL || (srb->state & SRB_DISCONNECT) == 0) { - /* - * abort command - */ - srb = &sc->sc_tempsrb; - srb->state = SRB_UNEXPECT_RESEL; - dcb->actsrb = srb; - srb->msgout[0] = MSG_ABORT; - trm_msgout_abort(sc, srb); - } else { - if (dcb->flag & ABORT_DEV_) { - srb->state = SRB_ABORT_SENT; - srb->msgout[0] = MSG_ABORT; - trm_msgout_abort(sc, srb); - } else - srb->state = SRB_DATA_XFER; + /* Read Reselected Target Id and LUN */ + target = bus_space_read_1(iot, ioh, TRM_SCSI_TARGETID); + lun = bus_space_read_1(iot, ioh, TRM_SCSI_IDMSG) & 0x07; + ti = &sc->sc_tinfo[target]; + li = ti->linfo[lun]; + DPRINTF(("target = %d, lun = %d\n", target, lun)); + + /* + * Check to see if we are running an un-tagged command. + * Otherwise ack the IDENTIFY and wait for a tag message. + */ + if (li != NULL) { + if (li->untagged != NULL && li->busy) { + sc->sc_actsrb = li->untagged; + sc->sc_state = TRM_DATA_XFER; + } else { + sc->resel_target = target; + sc->resel_lun = lun; + /* XXX XXX XXX */ + sc->sc_flag |= WAIT_TAGMSG; + } + } + + if ((ti->flag & USE_TAG_QUEUING) == 0 && + sc->sc_actsrb == NULL) { + printf("%s: reselect from target %d lun %d " + "without nexus; sending abort\n", + sc->sc_dev.dv_xname, target, lun); + sc->sc_state = TRM_UNEXPECT_RESEL; + sc->sc_msgbuf[0] = MSG_ABORT_TAG; + sc->sc_msgcnt = 1; + bus_space_write_2(iot, ioh, + TRM_SCSI_CONTROL, DO_SETATN); } } - srb->phase = PH_BUS_FREE; /* SCSI bus free Phase */ + sc->sc_phase = PH_BUS_FREE; /* SCSI bus free Phase */ /* * Program HA ID, target ID, period and offset */ /* target ID */ - bus_space_write_1(iot, ioh, TRM_SCSI_TARGETID, id); + bus_space_write_1(iot, ioh, TRM_SCSI_TARGETID, target); /* host ID */ bus_space_write_1(iot, ioh, TRM_SCSI_HOSTID, sc->sc_id); /* period */ - bus_space_write_1(iot, ioh, TRM_SCSI_SYNC, dcb->synctl); + bus_space_write_1(iot, ioh, TRM_SCSI_SYNC, ti->synctl); /* offset */ - bus_space_write_1(iot, ioh, TRM_SCSI_OFFSET, dcb->offset); + bus_space_write_1(iot, ioh, TRM_SCSI_OFFSET, ti->offset); /* it's important for atn stop */ bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_DATALATCH); - DELAY(30); /* * SCSI cammand */ @@ -2150,20 +2165,13 @@ trm_reselect(sc) * Signal completion to the generic SCSI driver */ static void -trm_srb_done(sc, dcb, srb) +trm_done(sc, srb) struct trm_softc *sc; - struct trm_dcb *dcb; struct trm_srb *srb; { struct scsipi_xfer *xs = srb->xs; - struct scsipi_inquiry_data *ptr; - struct trm_dcb *tempdcb; - int i, j, id, lun, s; - u_int8_t bval; -#ifdef TRM_DEBUG - printf("trm_srb_done..................\n"); -#endif + DPRINTF(("trm_done..................\n")); if (xs == NULL) return; @@ -2186,25 +2194,31 @@ trm_srb_done(sc, dcb, srb) */ xs->status = srb->tastat; + DPRINTF(("xs->status = 0x%02x\n", xs->status)); + switch (xs->status) { case SCSI_OK: /* * process initiator status...... * Adapter (initiator) status */ - if (srb->hastat & H_OVER_UNDER_RUN) { + if ((srb->hastat & H_OVER_UNDER_RUN) != 0) { + printf("%s: over/under run error\n", + sc->sc_dev.dv_xname); srb->tastat = 0; /* Illegal length (over/under run) */ xs->error = XS_DRIVER_STUFFUP; - } else if (srb->srbstat & PARITY_ERROR) { -#ifdef TRM_DEBUG - printf("%s: driver stuffup at %s %d\n", - sc->sc_dev.dv_xname, __FILE__, __LINE__); -#endif + } else if ((srb->flag & PARITY_ERROR) != 0) { + printf("%s: parity error\n", + sc->sc_dev.dv_xname); /* Driver failed to perform operation */ - xs->error = XS_DRIVER_STUFFUP; + xs->error = XS_DRIVER_STUFFUP; /* XXX */ + } else if ((srb->flag & SRB_TIMEOUT) != 0) { + xs->resid = srb->buflen; + xs->error = XS_TIMEOUT; } else { /* No error */ + xs->resid = srb->buflen; srb->hastat = 0; if (srb->flag & AUTO_REQSENSE) { /* there is no error, (sense is invalid) */ @@ -2215,9 +2229,10 @@ trm_srb_done(sc, dcb, srb) } } break; + case SCSI_CHECK: if ((srb->flag & AUTO_REQSENSE) != 0 || - trm_request_sense(sc, dcb, srb) != 0) { + trm_request_sense(sc, srb) != 0) { printf("%s: request sense failed\n", sc->sc_dev.dv_xname); xs->error = XS_DRIVER_STUFFUP; @@ -2225,269 +2240,60 @@ trm_srb_done(sc, dcb, srb) } xs->error = XS_SENSE; return; - case SCSI_QUEUE_FULL: - dcb->maxcmd = dcb->gosrb_cnt - 1; - trm_rewait_srb(dcb, srb); - srb->hastat = 0; - srb->tastat = 0; - break; + case SCSI_SEL_TIMEOUT: srb->hastat = H_SEL_TIMEOUT; srb->tastat = 0; - xs->error = XS_TIMEOUT; + xs->error = XS_SELTIMEOUT; break; + + case SCSI_QUEUE_FULL: case SCSI_BUSY: xs->error = XS_BUSY; break; + case SCSI_RESV_CONFLICT: -#ifdef TRM_DEBUG - printf("%s: target reserved at ", sc->sc_dev.dv_xname); - printf("%s %d\n", __FILE__, __LINE__); -#endif + DPRINTF(("%s: target reserved at ", sc->sc_dev.dv_xname)); + DPRINTF(("%s %d\n", __FILE__, __LINE__)); xs->error = XS_BUSY; break; + default: srb->hastat = 0; -#ifdef TRM_DEBUG - printf("%s: driver stuffup at %s %d\n", - sc->sc_dev.dv_xname, __FILE__, __LINE__); -#endif + printf("%s: trm_done(): unknown status = %02x\n", + sc->sc_dev.dv_xname, xs->status); xs->error = XS_DRIVER_STUFFUP; break; } - id = srb->xs->xs_periph->periph_target; - lun = srb->xs->xs_periph->periph_lun; - if (sc->devscan[id][lun]) { - /* - * if SCSI command in "scan devices" duty - * XXX XXX XXX should not be done here! XXX XXX XXX - */ - if (srb->cmd[0] == INQUIRY) { - /* - * SCSI command phase: inquiry scsi device data - * (type,capacity,manufacture.... - */ - if (xs->error == XS_TIMEOUT) - goto NO_DEV; - - ptr = (struct scsipi_inquiry_data *)xs->data; - bval = ptr->device & SID_TYPE; - - if (bval == T_NODEVICE) { - NO_DEV: -#ifdef TRM_DEBUG - printf("trm_srb_done NO Device: "); - printf("id= %d ,lun= %d\n", id, lun); -#endif - s = splbio(); - /* - * dcb Q link - * move the head of DCB to temdcb - */ - tempdcb = sc->sc_linkdcb; - - /* - * search current DCB for pass link - */ - while (tempdcb->next != dcb) - tempdcb = tempdcb->next; - - /* - * when the current DCB been found - * than connect current DCB tail - * to the DCB tail that before current DCB - */ - tempdcb->next = dcb->next; - - /* - * if there was only one DCB ,connect his - * tail to his head - */ - if (sc->sc_linkdcb == dcb) - sc->sc_linkdcb = tempdcb->next; - - if (sc->sc_roundcb == dcb) - sc->sc_roundcb = tempdcb->next; - - /* - * if no device than free this device DCB - * free( dcb, M_DEVBUF); - */ - sc->devcnt--; -#ifdef TRM_DEBUG - printf("sc->devcnt=%d\n", sc->devcnt); -#endif - if (sc->devcnt == 0) { - sc->sc_linkdcb = NULL; - sc->sc_roundcb = NULL; - } - /* no device set scan device flag=0 */ - sc->devscan[id][lun] = 0; - i = 0; - j = 0; - while (i <= sc->maxid) { - while (j < 8) { - if (sc->devscan[i][j] == 1) { - sc->devscan_end = 0; - splx(s); - goto exit; - } else - sc->devscan_end = 1; - - j++; - } - j = 0; - i++; - } - splx(s); - } else { - if (bval == T_DIRECT || bval == T_OPTICAL) { - if ((((ptr->version & 0x07) >= 2) || - ((ptr->response_format & 0x0F) - == 2)) && - (ptr->flags3 & SID_CmdQue) && - (dcb->tacfg & NTC_DO_TAG_QUEUING) && - (dcb->tacfg & NTC_DO_DISCONNECT)) { - dcb->maxcmd = sc->maxtag; - dcb->mode |= EN_TAG_QUEUING; - dcb->tagmask = 0; - } else - dcb->mode |= EN_ATN_STOP; - } - } - } + trm_dequeue(sc, srb); + if (srb == sc->sc_actsrb) { + sc->sc_actsrb = NULL; + trm_sched(sc); } -exit: - trm_release_srb(sc, dcb, srb); - trm_wait_srb(sc); - xs->xs_status |= XS_STS_DONE; + + TAILQ_INSERT_TAIL(&sc->sc_freesrb, srb, next); + /* Notify cmd done */ scsipi_done(xs); } -static void -trm_release_srb(sc, dcb, srb) - struct trm_softc *sc; - struct trm_dcb *dcb; - struct trm_srb *srb; -{ - struct trm_srb *psrb; - int s; - - s = splbio(); - if (srb == dcb->gosrb) - dcb->gosrb = srb->next; - else { - psrb = dcb->gosrb; - while (psrb->next != srb) - psrb = psrb->next; - - psrb->next = srb->next; - if (srb == dcb->last_gosrb) - dcb->last_gosrb = psrb; - } - srb->next = sc->sc_freesrb; - sc->sc_freesrb = srb; - dcb->gosrb_cnt--; - splx(s); - return; -} - -static void -trm_doing_srb_done(sc) - struct trm_softc *sc; -{ - struct trm_dcb *dcb, *pdcb; - struct trm_srb *psrb, *psrb2; - struct scsipi_xfer *xs; - int i; - - dcb = sc->sc_linkdcb; - if (dcb == NULL) - return; - - pdcb = dcb; - do { - psrb = pdcb->gosrb; - for (i = 0; i < pdcb->gosrb_cnt; i++) { - psrb2 = psrb->next; - xs = psrb->xs; - xs->error = XS_TIMEOUT; - /* ReleaseSRB( dcb, srb ); */ - psrb->next = sc->sc_freesrb; - sc->sc_freesrb = psrb; - scsipi_done(xs); - psrb = psrb2; - } - pdcb->gosrb_cnt = 0;; - pdcb->gosrb = NULL; - pdcb->tagmask = 0; - pdcb = pdcb->next; - } - while (pdcb != dcb); -} - -static void -trm_reset_scsi_bus(sc) - struct trm_softc *sc; -{ - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; - int s; - - s = splbio(); - - sc->sc_flag |= RESET_DEV; - bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_RSTSCSI); - while ((bus_space_read_2(iot, ioh, TRM_SCSI_INTSTATUS) & - INT_SCSIRESET) == 0) - ; - - splx(s); -} - -static void -trm_scsi_reset_detect(sc) - struct trm_softc *sc; -{ - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; - int s; - -#ifdef TRM_DEBUG - printf("trm_scsi_reset_detect...............\n"); -#endif - DELAY(1000000); /* delay 1 sec */ - - s = splbio(); - - bus_space_write_1(iot, ioh, TRM_DMA_CONTROL, STOPDMAXFER); - bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_CLRFIFO); - - if (sc->sc_flag & RESET_DEV) { - sc->sc_flag |= RESET_DONE; - } else { - sc->sc_flag |= RESET_DETECT; - trm_reset_device(sc); - /* trm_doing_srb_done( sc ); ???? */ - trm_recover_srb(sc); - sc->sc_actdcb = NULL; - sc->sc_flag = 0; - trm_wait_srb(sc); - } - splx(s); -} - static int -trm_request_sense(sc, dcb, srb) +trm_request_sense(sc, srb) struct trm_softc *sc; - struct trm_dcb *dcb; struct trm_srb *srb; { - struct scsipi_xfer *xs = srb->xs; - struct scsipi_sense *ss; - int error, lun = xs->xs_periph->periph_lun; + struct scsipi_xfer *xs; + struct scsipi_periph *periph; + struct trm_tinfo *ti; + struct trm_linfo *li; + struct scsipi_sense *ss = (struct scsipi_sense *)srb->cmd; + int error; + + DPRINTF(("trm_request_sense...\n")); + + xs = srb->xs; + periph = xs->xs_periph; srb->flag |= AUTO_REQSENSE; @@ -2495,9 +2301,8 @@ trm_request_sense(sc, dcb, srb) srb->hastat = 0; srb->tastat = 0; - ss = (struct scsipi_sense *)srb->cmd; ss->opcode = REQUEST_SENSE; - ss->byte2 = lun << SCSI_CMD_LUN_SHIFT; + ss->byte2 = periph->periph_lun << SCSI_CMD_LUN_SHIFT; ss->unused[0] = ss->unused[1] = 0; ss->length = sizeof(struct scsipi_sense_data); ss->control = 0; @@ -2520,427 +2325,102 @@ trm_request_sense(sc, dcb, srb) bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, srb->sgoffset, TRM_SG_SIZE, BUS_DMASYNC_PREWRITE); - if (trm_start_scsi(sc, dcb, srb)) - /* - * If trm_start_scsi return 1: current interrupt status - * is interrupt disreenable. It's said that SCSI processor - * has more one SRB need to do. - */ - trm_rewait_srb(dcb, srb); + ti = &sc->sc_tinfo[periph->periph_target]; + li = ti->linfo[periph->periph_lun]; + if (li->busy > 0) + li->busy = 0; + trm_dequeue(sc, srb); + li->untagged = srb; /* must be executed first to fix C/A */ + li->busy = 2; + + if (srb == sc->sc_actsrb) + trm_select(sc, srb); + else { + TAILQ_INSERT_HEAD(&sc->sc_readysrb, srb, next); + if (sc->sc_actsrb == NULL) + trm_sched(sc); + } return 0; } static void -trm_msgout_abort(sc, srb) +trm_dequeue(sc, srb) struct trm_softc *sc; struct trm_srb *srb; { - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; + struct scsipi_periph *periph; + struct trm_tinfo *ti; + struct trm_linfo *li; - srb->msgcnt = 1; - bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_SETATN); - srb->dcb->flag &= ~ABORT_DEV_; + periph = srb->xs->xs_periph; + ti = &sc->sc_tinfo[periph->periph_target]; + li = ti->linfo[periph->periph_lun]; + + if (li->untagged == srb) { + li->busy = 0; + li->untagged = NULL; + } + if (srb->tag[0] != 0 && li->queued[srb->tag[1]] != NULL) { + li->queued[srb->tag[1]] = NULL; + li->used--; + } } -/* - * initialize the internal structures for a given DCB - */ static void -trm_init_dcb(sc, dcb, xs) +trm_reset_scsi_bus(sc) struct trm_softc *sc; - struct trm_dcb *dcb; - struct scsipi_xfer *xs; { - struct trm_nvram *eeprom; - struct trm_dcb *tempdcb; - int index, id, lun, s; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + int timeout, s; - id = xs->xs_periph->periph_target; - lun = xs->xs_periph->periph_lun; + DPRINTF(("trm_reset_scsi_bus.........\n")); s = splbio(); - if (sc->sc_linkdcb == 0) { - sc->sc_linkdcb = dcb; - /* - * RunRobin impersonate the role that let each device had - * good proportion about SCSI command proceeding. - */ - sc->sc_roundcb = dcb; - dcb->next = dcb; - } else { - tempdcb = sc->sc_linkdcb; - /* search the last nod of DCB link */ - while (tempdcb->next != sc->sc_linkdcb) - tempdcb = tempdcb->next; - /* connect current DCB with last DCB tail */ - tempdcb->next = dcb; - /* connect current DCB tail to this DCB Q head */ - dcb->next = sc->sc_linkdcb; - } - splx(s); - - sc->devcnt++; - dcb->id = id; - dcb->lun = lun; - dcb->waitsrb = NULL; - dcb->gosrb = NULL; - dcb->gosrb_cnt = 0; - dcb->actsrb = NULL; - dcb->tagmask = 0; - dcb->maxcmd = 1; - dcb->flag = 0; - - eeprom = &sc->sc_eeprom; - dcb->tacfg = eeprom->target[id].config0; - /* - * disconnect enable? - */ - dcb->idmsg = MSG_IDENTIFY(lun, dcb->tacfg & NTC_DO_DISCONNECT); - /* - * tag Qing enable? - * wide nego, sync nego enable? - */ - dcb->synctl = 0; - dcb->offset = 0; - index = eeprom->target[id].period & 0x07; - dcb->period = trm_clock_period[index]; - dcb->mode = 0; - if ((dcb->tacfg & NTC_DO_WIDE_NEGO) && (sc->sc_config & HCC_WIDE_CARD)) - /* enable wide nego */ - dcb->mode |= WIDE_NEGO_ENABLE; - - if ((dcb->tacfg & NTC_DO_SYNC_NEGO) && (lun == 0 || sc->cur_offset > 0)) - /* enable sync nego */ - dcb->mode |= SYNC_NEGO_ENABLE; -} - -static void -trm_link_srb(sc) - struct trm_softc *sc; -{ - struct trm_srb *srb; - int i; - - sc->sc_srb = malloc(sizeof(struct trm_srb) * TRM_MAX_SRB, - M_DEVBUF, M_NOWAIT|M_ZERO); - if (sc->sc_srb == NULL) { - printf("%s: can not allocate SRB\n", sc->sc_dev.dv_xname); - return; - } - - for (i = 0, srb = sc->sc_srb; i < TRM_MAX_SRB; i++, srb++) { - srb->sgentry = sc->sc_sglist + TRM_MAX_SG_ENTRIES * i; - srb->sgoffset = TRM_SG_SIZE * i; - srb->sgaddr = sc->sc_dmamap->dm_segs[0].ds_addr + srb->sgoffset; - /* - * map all SRB space to SRB_array - */ - if (bus_dmamap_create(sc->sc_dmat, - MAXPHYS, TRM_MAX_SG_ENTRIES, MAXPHYS, 0, - BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &srb->dmap)) { - printf("%s: unable to create DMA transfer map...\n", - sc->sc_dev.dv_xname); - free(sc->sc_srb, M_DEVBUF); - return; - } - if (i != TRM_MAX_SRB - 1) { - /* - * link all SRB - */ - srb->next = srb + 1; -#ifdef TRM_DEBUG - printf("srb->next = %8x ", (int) (srb + 1)); -#endif - } else { - /* - * load NULL to NextSRB of the last SRB - */ - srb->next = NULL; - } -#ifdef TRM_DEBUG - printf("srb = %8x\n", (int) srb); -#endif - } - return; -} - -/* - * initialize the internal structures for a given SCSI host - */ -static void -trm_init_sc(sc) - struct trm_softc *sc; -{ - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; - struct trm_nvram *eeprom; - int i, j; - - eeprom = &sc->sc_eeprom; - sc->maxid = 7; - sc->sc_config = HCC_AUTOTERM | HCC_PARITY; - if (bus_space_read_1(iot, ioh, TRM_GEN_STATUS) & WIDESCSI) { - sc->sc_config |= HCC_WIDE_CARD; - sc->maxid = 15; - } - if (eeprom->channel_cfg & NAC_POWERON_SCSI_RESET) - sc->sc_config |= HCC_SCSI_RESET; - - sc->sc_linkdcb = NULL; - sc->sc_roundcb = NULL; - sc->sc_actdcb = NULL; - sc->sc_id = eeprom->scsi_id; - sc->devcnt = 0; - sc->maxtag = 2 << eeprom->max_tag; - sc->sc_flag = 0; - sc->devscan_end = 0; - /* - * link all device's SRB Q of this adapter - */ - trm_link_srb(sc); - sc->sc_freesrb = sc->sc_srb; - /* allocate DCB array for scan device */ - for (i = 0; i <= sc->maxid; i++) - if (sc->sc_id != i) - for (j = 0; j < 8; j++) { - sc->devscan[i][j] = 1; - sc->devflag[i][j] = 0; - sc->sc_dcb[i][j] = - malloc(sizeof(struct trm_dcb), - M_DEVBUF, M_WAITOK); - } - -#ifdef TRM_DEBUG - printf("sizeof(struct trm_dcb)= %8x\n", sizeof(struct trm_dcb)); - printf("sizeof(struct trm_softc)= %8x\n", sizeof(struct trm_softc)); - printf("sizeof(struct trm_srb)= %8x\n", sizeof(struct trm_srb)); -#endif - sc->sc_adapter.adapt_dev = &sc->sc_dev; - sc->sc_adapter.adapt_nchannels = 1; - sc->sc_adapter.adapt_openings = TRM_MAX_SRB; - sc->sc_adapter.adapt_max_periph = TRM_MAX_SRB; - sc->sc_adapter.adapt_request = trm_scsipi_request; - sc->sc_adapter.adapt_minphys = minphys; - - sc->sc_channel.chan_adapter = &sc->sc_adapter; - sc->sc_channel.chan_bustype = &scsi_bustype; - sc->sc_channel.chan_channel = 0; - sc->sc_channel.chan_ntargets = sc->maxid + 1; - sc->sc_channel.chan_nluns = 8; - sc->sc_channel.chan_id = sc->sc_id; -} - -/* - * write sc_eeprom 128 bytes to seeprom - */ -static void -trm_eeprom_write_all(sc, eeprom) - struct trm_softc *sc; - struct trm_nvram *eeprom; -{ - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; - u_int8_t *buf = (u_int8_t *)eeprom; - u_int8_t addr; - - /* Enable SEEPROM */ - bus_space_write_1(iot, ioh, TRM_GEN_CONTROL, - bus_space_read_1(iot, ioh, TRM_GEN_CONTROL) | EN_EEPROM); - - /* - * Write enable - */ - trm_eeprom_write_cmd(sc, 0x04, 0xFF); - bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, 0); - trm_wait_30us(); - - for (addr = 0; addr < 128; addr++, buf++) - trm_eeprom_set_data(sc, addr, *buf); - - /* - * Write disable - */ - trm_eeprom_write_cmd(sc, 0x04, 0x00); - bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, 0); - trm_wait_30us(); - - /* Disable SEEPROM */ - bus_space_write_1(iot, ioh, TRM_GEN_CONTROL, - bus_space_read_1(iot, ioh, TRM_GEN_CONTROL) & ~EN_EEPROM); -} - -/* - * write one byte to seeprom - */ -static void -trm_eeprom_set_data(sc, addr, data) - struct trm_softc *sc; - u_int8_t addr; - u_int8_t data; -{ - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; - int i; - u_int8_t send; - - /* - * Send write command & address - */ - trm_eeprom_write_cmd(sc, 0x05, addr); - /* - * Write data - */ - for (i = 0; i < 8; i++, data <<= 1) { - send = NVR_SELECT; - if (data & 0x80) /* Start from bit 7 */ - send |= NVR_BITOUT; - - bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, send); - trm_wait_30us(); - bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, send | NVR_CLOCK); - trm_wait_30us(); - } - bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, NVR_SELECT); - trm_wait_30us(); - /* - * Disable chip select - */ - bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, 0); - trm_wait_30us(); - bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, NVR_SELECT); - trm_wait_30us(); - /* - * Wait for write ready - */ - for (;;) { - bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, - NVR_SELECT | NVR_CLOCK); - trm_wait_30us(); - bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, NVR_SELECT); - trm_wait_30us(); - if (bus_space_read_1(iot, ioh, TRM_GEN_NVRAM) & NVR_BITIN) + sc->sc_flag |= RESET_DEV; + bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_RSTSCSI); + for (timeout = 20000; timeout >= 0; timeout--) { + DELAY(1); + if ((bus_space_read_2(iot, ioh, TRM_SCSI_INTSTATUS) & + INT_SCSIRESET) == 0) break; } - /* - * Disable chip select - */ - bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, 0); + if (timeout == 0) + printf(": scsibus reset timeout\n"); + + splx(s); } -/* - * read seeprom 128 bytes to sc_eeprom - */ static void -trm_eeprom_read_all(sc, eeprom) +trm_scsi_reset_detect(sc) struct trm_softc *sc; - struct trm_nvram *eeprom; { bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; - u_int8_t *buf = (u_int8_t *)eeprom; - u_int8_t addr; + int s; - /* - * Enable SEEPROM - */ - bus_space_write_1(iot, ioh, TRM_GEN_CONTROL, - bus_space_read_1(iot, ioh, TRM_GEN_CONTROL) | EN_EEPROM); + DPRINTF(("trm_scsi_reset_detect...............\n")); + DELAY(1000000); /* delay 1 sec */ - for (addr = 0; addr < 128; addr++, buf++) - *buf = trm_eeprom_get_data(sc, addr); + s = splbio(); - /* - * Disable SEEPROM - */ - bus_space_write_1(iot, ioh, TRM_GEN_CONTROL, - bus_space_read_1(iot, ioh, TRM_GEN_CONTROL) & ~EN_EEPROM); + bus_space_write_1(iot, ioh, TRM_DMA_CONTROL, STOPDMAXFER); + bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_CLRFIFO); + + if (sc->sc_flag & RESET_DEV) { + sc->sc_flag |= RESET_DONE; + } else { + sc->sc_flag |= RESET_DETECT; + sc->sc_actsrb = NULL; + sc->sc_flag = 0; + trm_sched(sc); + } + splx(s); } /* - * read one byte from seeprom - */ -static u_int8_t -trm_eeprom_get_data(sc, addr) - struct trm_softc *sc; - u_int8_t addr; -{ - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; - int i; - u_int8_t read, data = 0; - - /* - * Send read command & address - */ - trm_eeprom_write_cmd(sc, 0x06, addr); - - for (i = 0; i < 8; i++) { /* Read data */ - bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, - NVR_SELECT | NVR_CLOCK); - trm_wait_30us(); - bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, NVR_SELECT); - /* - * Get data bit while falling edge - */ - read = bus_space_read_1(iot, ioh, TRM_GEN_NVRAM); - data <<= 1; - if (read & NVR_BITIN) - data |= 1; - - trm_wait_30us(); - } - /* - * Disable chip select - */ - bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, 0); - return (data); -} - -/* - * write SB and Op Code into seeprom - */ -static void -trm_eeprom_write_cmd(sc, cmd, addr) - struct trm_softc *sc; - u_int8_t cmd; - u_int8_t addr; -{ - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; - int i; - u_int8_t send; - - /* Program SB+OP code */ - for (i = 0; i < 3; i++, cmd <<= 1) { - send = NVR_SELECT; - if (cmd & 0x04) /* Start from bit 2 */ - send |= NVR_BITOUT; - - bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, send); - trm_wait_30us(); - bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, send | NVR_CLOCK); - trm_wait_30us(); - } - - /* Program address */ - for (i = 0; i < 7; i++, addr <<= 1) { - send = NVR_SELECT; - if (addr & 0x40) /* Start from bit 6 */ - send |= NVR_BITOUT; - - bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, send); - trm_wait_30us(); - bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, send | NVR_CLOCK); - trm_wait_30us(); - } - bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, NVR_SELECT); - trm_wait_30us(); -} - -/* - * read seeprom 128 bytes to sc_eeprom and check checksum. + * read seeprom 128 bytes to struct eeprom and check checksum. * If it is wrong, updated with default value. */ static void @@ -2953,9 +2433,7 @@ trm_check_eeprom(sc, eeprom) u_int16_t chksum; int i; -#ifdef TRM_DEBUG - printf("\n trm_check_eeprom......\n"); -#endif + DPRINTF(("trm_check_eeprom......\n")); trm_eeprom_read_all(sc, eeprom); ep = (u_int16_t *)eeprom; chksum = 0; @@ -2963,9 +2441,7 @@ trm_check_eeprom(sc, eeprom) chksum += le16toh(*ep++); if (chksum != TRM_NVRAM_CKSUM) { -#ifdef TRM_DEBUG - printf("TRM_S1040 EEPROM Check Sum ERROR (load default).\n"); -#endif + DPRINTF(("TRM_S1040 EEPROM Check Sum ERROR (load default).\n")); /* * Checksum error, load default */ @@ -3013,214 +2489,208 @@ trm_check_eeprom(sc, eeprom) } /* - * initialize the SCSI chip ctrl registers + * write struct eeprom 128 bytes to seeprom */ static void -trm_init_adapter(sc) +trm_eeprom_write_all(sc, eeprom) struct trm_softc *sc; + struct trm_nvram *eeprom; { bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; - u_int8_t bval; + u_int8_t *buf = (u_int8_t *)eeprom; + u_int8_t addr; - /* program configuration 0 */ - bval = PHASELATCH | INITIATOR | BLOCKRST; - if (sc->sc_config & HCC_PARITY) - bval |= PARITYCHECK; - bus_space_write_1(iot, ioh, TRM_SCSI_CONFIG0, bval); + /* Enable SEEPROM */ + bus_space_write_1(iot, ioh, TRM_GEN_CONTROL, + bus_space_read_1(iot, ioh, TRM_GEN_CONTROL) | EN_EEPROM); - /* program configuration 1 */ - bus_space_write_1(iot, ioh, TRM_SCSI_CONFIG1, - ACTIVE_NEG | ACTIVE_NEGPLUS); + /* + * Write enable + */ + trm_eeprom_write_cmd(sc, 0x04, 0xFF); + bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, 0); + trm_eeprom_wait(); - /* 250ms selection timeout */ - bus_space_write_1(iot, ioh, TRM_SCSI_TIMEOUT, SEL_TIMEOUT); + for (addr = 0; addr < 128; addr++, buf++) + trm_eeprom_set_data(sc, addr, *buf); - /* Mask all the interrupt */ - bus_space_write_1(iot, ioh, TRM_DMA_INTEN, 0); - bus_space_write_1(iot, ioh, TRM_SCSI_INTEN, 0); + /* + * Write disable + */ + trm_eeprom_write_cmd(sc, 0x04, 0x00); + bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, 0); + trm_eeprom_wait(); - /* Reset SCSI module */ - bus_space_write_2(iot, ioh, TRM_SCSI_CONTROL, DO_RSTMODULE); - - /* program Host ID */ - bus_space_write_1(iot, ioh, TRM_SCSI_HOSTID, sc->sc_id); - - /* set ansynchronous transfer */ - bus_space_write_1(iot, ioh, TRM_SCSI_OFFSET, 0); - - /* Trun LED control off */ - bus_space_write_2(iot, ioh, TRM_GEN_CONTROL, - bus_space_read_2(iot, ioh, TRM_GEN_CONTROL) & ~EN_LED); - - /* DMA config */ - bus_space_write_2(iot, ioh, TRM_DMA_CONFIG, - bus_space_read_2(iot, ioh, TRM_DMA_CONFIG) | DMA_ENHANCE); - - /* Clear pending interrupt status */ - bus_space_read_1(iot, ioh, TRM_SCSI_INTSTATUS); - - /* Enable SCSI interrupt */ - bus_space_write_1(iot, ioh, TRM_SCSI_INTEN, - EN_SELECT | EN_SELTIMEOUT | EN_DISCONNECT | EN_RESELECTED | - EN_SCSIRESET | EN_BUSSERVICE | EN_CMDDONE); - bus_space_write_1(iot, ioh, TRM_DMA_INTEN, EN_SCSIINTR); + /* Disable SEEPROM */ + bus_space_write_1(iot, ioh, TRM_GEN_CONTROL, + bus_space_read_1(iot, ioh, TRM_GEN_CONTROL) & ~EN_EEPROM); } /* - * initialize the internal structures for a given SCSI host - */ -static int -trm_init(sc) - struct trm_softc *sc; -{ - bus_dma_segment_t seg; - int error, rseg, all_sgsize; - - /* - * EEPROM CHECKSUM - */ - trm_check_eeprom(sc, &sc->sc_eeprom); - /* - * MEMORY ALLOCATE FOR ADAPTER CONTROL BLOCK - * allocate the space for all SCSI control blocks (SRB) for DMA memory - */ - all_sgsize = TRM_MAX_SRB * TRM_SG_SIZE; - if ((error = bus_dmamem_alloc(sc->sc_dmat, all_sgsize, PAGE_SIZE, - 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) { - printf("%s: unable to allocate SCSI REQUEST BLOCKS, " - "error = %d\n", sc->sc_dev.dv_xname, error); - return (-1); - } - if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, - all_sgsize, (caddr_t *) &sc->sc_sglist, - BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) { - printf("%s: unable to map SCSI REQUEST BLOCKS, " - "error = %d\n", sc->sc_dev.dv_xname, error); - return (-1); - } - if ((error = bus_dmamap_create(sc->sc_dmat, all_sgsize, 1, - all_sgsize, 0, BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) { - printf("%s: unable to create SRB DMA maps, " - "error = %d\n", sc->sc_dev.dv_xname, error); - return (-1); - } - if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, - sc->sc_sglist, all_sgsize, NULL, BUS_DMA_NOWAIT)) != 0) { - printf("%s: unable to load SRB DMA maps, " - "error = %d\n", sc->sc_dev.dv_xname, error); - return (-1); - } -#ifdef TRM_DEBUG - printf("\n\n%s: all_sgsize=%x\n", sc->sc_dev.dv_xname, all_sgsize); -#endif - memset(sc->sc_sglist, 0, all_sgsize); - trm_init_sc(sc); - trm_init_adapter(sc); - trm_reset(sc); - return (0); -} - -/* - * attach and init a host adapter + * write one byte to seeprom */ static void -trm_attach(parent, self, aux) - struct device *parent; - struct device *self; - void *aux; +trm_eeprom_set_data(sc, addr, data) + struct trm_softc *sc; + u_int8_t addr; + u_int8_t data; { - struct pci_attach_args *const pa = aux; - struct trm_softc *sc = (void *) self; - bus_space_tag_t iot; /* bus space tag */ - bus_space_handle_t ioh; /* bus space handle */ - pci_intr_handle_t ih; - pcireg_t command; - const char *intrstr; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + int i; + u_int8_t send; /* - * These cards do not allow memory mapped accesses - * pa_pc: chipset tag - * pa_tag: pci tag + * Send write command & address */ - command = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); - if ((command & (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MASTER_ENABLE)) != - (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MASTER_ENABLE)) { - command |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MASTER_ENABLE; - pci_conf_write(pa->pa_pc, pa->pa_tag, - PCI_COMMAND_STATUS_REG, command); - } + trm_eeprom_write_cmd(sc, 0x05, addr); /* - * mask for get correct base address of pci IO port + * Write data */ - if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_IO, 0, - &iot, &ioh, NULL, NULL)) { - printf("%s: unable to map registers\n", sc->sc_dev.dv_xname); - return; - } - /* - * test checksum of eeprom..& initial "ACB" adapter control block... - */ - sc->sc_iot = iot; - sc->sc_ioh = ioh; - sc->sc_dmat = pa->pa_dmat; - if (trm_init(sc)) { - /* - * Error during initialization! - */ - printf(": Error during initialization\n"); - return; - } - /* - * Now try to attach all the sub-devices - */ - if (sc->sc_config & HCC_WIDE_CARD) - printf(": Tekram DC395UW/F (TRM-S1040) Fast40 " - "Ultra Wide SCSI Adapter\n"); - else - printf(": Tekram DC395U, DC315/U (TRM-S1040) Fast20 " - "Ultra SCSI Adapter\n"); + for (i = 0; i < 8; i++, data <<= 1) { + send = NVR_SELECT; + if (data & 0x80) /* Start from bit 7 */ + send |= NVR_BITOUT; - printf("%s: Adapter ID=%d, Max tag number=%d, %d SCBs\n", - sc->sc_dev.dv_xname, sc->sc_id, sc->maxtag, TRM_MAX_SRB); + bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, send); + trm_eeprom_wait(); + bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, send | NVR_CLOCK); + trm_eeprom_wait(); + } + bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, NVR_SELECT); + trm_eeprom_wait(); /* - * Now tell the generic SCSI layer about our bus. - * map and establish interrupt + * Disable chip select */ - if (pci_intr_map(pa, &ih)) { - printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname); - return; + bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, 0); + trm_eeprom_wait(); + bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, NVR_SELECT); + trm_eeprom_wait(); + /* + * Wait for write ready + */ + for (;;) { + bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, + NVR_SELECT | NVR_CLOCK); + trm_eeprom_wait(); + bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, NVR_SELECT); + trm_eeprom_wait(); + if (bus_space_read_1(iot, ioh, TRM_GEN_NVRAM) & NVR_BITIN) + break; } - intrstr = pci_intr_string(pa->pa_pc, ih); - - if (pci_intr_establish(pa->pa_pc, ih, IPL_BIO, trm_intr, sc) == NULL) { - printf("%s: couldn't establish interrupt", sc->sc_dev.dv_xname); - if (intrstr != NULL) - printf(" at %s", intrstr); - printf("\n"); - return; - } - if (intrstr != NULL) - printf("%s: interrupting at %s\n", - sc->sc_dev.dv_xname, intrstr); - config_found(&sc->sc_dev, &sc->sc_channel, scsiprint); + /* + * Disable chip select + */ + bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, 0); } /* - * match pci device + * read seeprom 128 bytes to struct eeprom */ -static int -trm_probe(parent, match, aux) - struct device *parent; - struct cfdata *match; - void *aux; +static void +trm_eeprom_read_all(sc, eeprom) + struct trm_softc *sc; + struct trm_nvram *eeprom; { - struct pci_attach_args *pa = aux; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + u_int8_t *buf = (u_int8_t *)eeprom; + u_int8_t addr; - if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_TEKRAM2) - switch (PCI_PRODUCT(pa->pa_id)) { - case PCI_PRODUCT_TEKRAM2_DC315: - return (1); - } - return (0); + /* + * Enable SEEPROM + */ + bus_space_write_1(iot, ioh, TRM_GEN_CONTROL, + bus_space_read_1(iot, ioh, TRM_GEN_CONTROL) | EN_EEPROM); + + for (addr = 0; addr < 128; addr++) + *buf++ = trm_eeprom_get_data(sc, addr); + + /* + * Disable SEEPROM + */ + bus_space_write_1(iot, ioh, TRM_GEN_CONTROL, + bus_space_read_1(iot, ioh, TRM_GEN_CONTROL) & ~EN_EEPROM); +} + +/* + * read one byte from seeprom + */ +static u_int8_t +trm_eeprom_get_data(sc, addr) + struct trm_softc *sc; + u_int8_t addr; +{ + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + int i; + u_int8_t read, data = 0; + + /* + * Send read command & address + */ + trm_eeprom_write_cmd(sc, 0x06, addr); + + for (i = 0; i < 8; i++) { /* Read data */ + bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, + NVR_SELECT | NVR_CLOCK); + trm_eeprom_wait(); + bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, NVR_SELECT); + /* + * Get data bit while falling edge + */ + read = bus_space_read_1(iot, ioh, TRM_GEN_NVRAM); + data <<= 1; + if (read & NVR_BITIN) + data |= 1; + + trm_eeprom_wait(); + } + /* + * Disable chip select + */ + bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, 0); + return (data); +} + +/* + * write SB and Op Code into seeprom + */ +static void +trm_eeprom_write_cmd(sc, cmd, addr) + struct trm_softc *sc; + u_int8_t cmd; + u_int8_t addr; +{ + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + int i; + u_int8_t send; + + /* Program SB+OP code */ + for (i = 0; i < 3; i++, cmd <<= 1) { + send = NVR_SELECT; + if (cmd & 0x04) /* Start from bit 2 */ + send |= NVR_BITOUT; + + bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, send); + trm_eeprom_wait(); + bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, send | NVR_CLOCK); + trm_eeprom_wait(); + } + + /* Program address */ + for (i = 0; i < 7; i++, addr <<= 1) { + send = NVR_SELECT; + if (addr & 0x40) /* Start from bit 6 */ + send |= NVR_BITOUT; + + bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, send); + trm_eeprom_wait(); + bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, send | NVR_CLOCK); + trm_eeprom_wait(); + } + bus_space_write_1(iot, ioh, TRM_GEN_NVRAM, NVR_SELECT); + trm_eeprom_wait(); }