File: [local] / sys / dev / ic / trm.c (download)
Revision 1.1.1.1 (vendor branch), Tue Mar 4 16:11:08 2008 UTC (16 years, 6 months ago) by nbrk
Branch: OPENBSD_4_2_BASE, MAIN
CVS Tags: jornada-partial-support-wip, HEAD Changes since 1.1: +0 -0 lines
Import of OpenBSD 4.2 release kernel tree with initial code to support
Jornada 720/728, StrongARM 1110-based handheld PC.
At this point kernel roots on NFS and boots into vfs_mountroot() and traps.
What is supported:
- glass console, Jornada framebuffer (jfb) works in 16bpp direct color mode
(needs some palette tweaks for non black/white/blue colors, i think)
- saic, SA11x0 interrupt controller (needs cleanup)
- sacom, SA11x0 UART (supported only as boot console for now)
- SA11x0 GPIO controller fully supported (but can't handle multiple interrupt
handlers on one gpio pin)
- sassp, SSP port on SA11x0 that attaches spibus
- Jornada microcontroller (jmcu) to control kbd, battery, etc throught
the SPI bus (wskbd attaches on jmcu, but not tested)
- tod functions seem work
- initial code for SA-1111 (chip companion) : this is TODO
Next important steps, i think:
- gpio and intc on sa1111
- pcmcia support for sa11x0 (and sa1111 help logic)
- REAL root on nfs when we have PCMCIA support (we may use any of supported pccard NICs)
- root on wd0! (using already supported PCMCIA-ATA)
|
/* $OpenBSD: trm.c,v 1.7 2005/12/03 16:53:16 krw Exp $
* ------------------------------------------------------------
* O.S : OpenBSD
* File Name : trm.c
* Device Driver for Tekram DC395U/UW/F,DC315/U
* PCI SCSI Bus Master Host Adapter
* (SCSI chip set used Tekram ASIC TRM-S1040)
*
* (C)Copyright 1995-1999 Tekram Technology Co., Ltd.
* (C)Copyright 2001-2002 Ashley R. Martens and Kenneth R Westerback
* ------------------------------------------------------------
* HISTORY:
*
* REV# DATE NAME DESCRIPTION
* 1.00 05/01/99 ERICH CHEN First released for NetBSD 1.4.x
* 1.01 00/00/00 MARTIN AKESSON Port to OpenBSD 2.8
* 1.02 09/19/01 ASHLEY MARTENS Cleanup and formatting
* 2.00 01/00/02 KENNETH R WESTERBACK Rewrite of the bus and code logic
* ------------------------------------------------------------
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ------------------------------------------------------------
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/buf.h>
#include <sys/device.h>
#include <machine/bus.h>
#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>
#include <scsi/scsi_message.h>
#include <dev/pci/pcidevs.h>
#include <dev/ic/trm.h>
/* #define TRM_DEBUG0 */
void trm_minphys(struct buf *);
void trm_initSRB(struct trm_scsi_req_q *);
void trm_check_eeprom(struct trm_adapter_nvram *, bus_space_tag_t, bus_space_handle_t);
void trm_read_all (struct trm_adapter_nvram *, bus_space_tag_t, bus_space_handle_t);
void trm_write_all (struct trm_adapter_nvram *, bus_space_tag_t, bus_space_handle_t);
void trm_set_data (bus_space_tag_t, bus_space_handle_t, u_int8_t, u_int8_t);
void trm_write_cmd(bus_space_tag_t, bus_space_handle_t, u_int8_t, u_int8_t);
u_int8_t trm_get_data(bus_space_tag_t, bus_space_handle_t, u_int8_t);
void trm_wait_30us(bus_space_tag_t, bus_space_handle_t);
int trm_scsi_cmd(struct scsi_xfer *);
struct trm_scsi_req_q *trm_GetFreeSRB(struct trm_softc *);
void trm_DataOutPhase0(struct trm_softc *, struct trm_scsi_req_q *, u_int8_t *);
void trm_DataInPhase0 (struct trm_softc *, struct trm_scsi_req_q *, u_int8_t *);
void trm_StatusPhase0 (struct trm_softc *, struct trm_scsi_req_q *, u_int8_t *);
void trm_MsgOutPhase0 (struct trm_softc *, struct trm_scsi_req_q *, u_int8_t *);
void trm_MsgInPhase0 (struct trm_softc *, struct trm_scsi_req_q *, u_int8_t *);
void trm_DataOutPhase1(struct trm_softc *, struct trm_scsi_req_q *, u_int8_t *);
void trm_DataInPhase1 (struct trm_softc *, struct trm_scsi_req_q *, u_int8_t *);
void trm_CommandPhase1(struct trm_softc *, struct trm_scsi_req_q *, u_int8_t *);
void trm_StatusPhase1 (struct trm_softc *, struct trm_scsi_req_q *, u_int8_t *);
void trm_MsgOutPhase1 (struct trm_softc *, struct trm_scsi_req_q *, u_int8_t *);
void trm_MsgInPhase1 (struct trm_softc *, struct trm_scsi_req_q *, u_int8_t *);
void trm_Nop (struct trm_softc *, struct trm_scsi_req_q *, u_int8_t *);
void trm_SetXferParams (struct trm_softc *, struct trm_dcb *, int);
void trm_DataIO_transfer(struct trm_softc *, struct trm_scsi_req_q *, u_int16_t);
int trm_StartSRB (struct trm_softc *, struct trm_scsi_req_q *);
void trm_ReleaseSRB (struct trm_softc *, struct trm_scsi_req_q *);
void trm_RewaitSRB (struct trm_softc *, struct trm_scsi_req_q *);
void trm_FinishSRB (struct trm_softc *, struct trm_scsi_req_q *);
void trm_RequestSense(struct trm_softc *, struct trm_scsi_req_q *);
void trm_initAdapter (struct trm_softc *);
void trm_Disconnect (struct trm_softc *);
void trm_Reselect (struct trm_softc *);
void trm_GoingSRB_Done (struct trm_softc *);
void trm_ScsiRstDetect (struct trm_softc *);
void trm_ResetSCSIBus (struct trm_softc *);
void trm_reset (struct trm_softc *);
void trm_StartWaitingSRB (struct trm_softc *);
void trm_ResetAllDevParam(struct trm_softc *);
void trm_RecoverSRB (struct trm_softc *);
void trm_linkSRB (struct trm_softc *);
void trm_initACB(struct trm_softc *, int);
void trm_ResetDevParam(struct trm_softc *, struct trm_dcb *, u_int8_t);
void trm_EnableMsgOut(struct trm_softc *, u_int8_t);
void trm_timeout(void *);
void trm_print_info(struct trm_softc *, struct trm_dcb *);
/*
* Define structures
*/
struct cfdriver trm_cd = {
NULL, "trm", DV_DULL
};
struct scsi_adapter trm_switch = {
trm_scsi_cmd,
trm_minphys,
NULL,
NULL
};
static struct scsi_device trm_device = {
NULL, /* Use default error handler */
NULL, /* have a queue, served by this */
NULL, /* have no async handler */
NULL, /* Use default 'done' routine */
};
/*
* ------------------------------------------------------------
*
* stateV = (void *) trm_SCSI_phase0[phase]
*
* ------------------------------------------------------------
*/
static void *trm_SCSI_phase0[8] = {
trm_DataOutPhase0, /* phase:0 */
trm_DataInPhase0, /* phase:1 */
trm_Nop, /* phase:2 */
trm_StatusPhase0, /* phase:3 */
trm_Nop, /* phase:4 */
trm_Nop, /* phase:5 */
trm_MsgOutPhase0, /* phase:6 */
trm_MsgInPhase0, /* phase:7 */
};
/*
* ------------------------------------------------------------
*
* stateV = (void *) trm_SCSI_phase1[phase]
*
* ------------------------------------------------------------
*/
static void *trm_SCSI_phase1[8] = {
trm_DataOutPhase1, /* phase:0 */
trm_DataInPhase1, /* phase:1 */
trm_CommandPhase1, /* phase:2 */
trm_StatusPhase1, /* phase:3 */
trm_Nop, /* phase:4 */
trm_Nop, /* phase:5 */
trm_MsgOutPhase1, /* phase:6 */
trm_MsgInPhase1, /* phase:7 */
};
struct trm_adapter_nvram trm_eepromBuf[TRM_MAX_ADAPTER_NUM];
/*
*Fast20: 000 50ns, 20.0 Mbytes/s
* 001 75ns, 13.3 Mbytes/s
* 010 100ns, 10.0 Mbytes/s
* 011 125ns, 8.0 Mbytes/s
* 100 150ns, 6.6 Mbytes/s
* 101 175ns, 5.7 Mbytes/s
* 110 200ns, 5.0 Mbytes/s
* 111 250ns, 4.0 Mbytes/s
*
*Fast40: 000 25ns, 40.0 Mbytes/s
* 001 50ns, 20.0 Mbytes/s
* 010 75ns, 13.3 Mbytes/s
* 011 100ns, 10.0 Mbytes/s
* 100 125ns, 8.0 Mbytes/s
* 101 150ns, 6.6 Mbytes/s
* 110 175ns, 5.7 Mbytes/s
* 111 200ns, 5.0 Mbytes/s
*/
/*
* real period:
*/
u_int8_t trm_clock_period[8] = {
/* nanosecond divided by 4 */
12, /* 48 ns 20 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 */
};
/*
* ------------------------------------------------------------
* Function : trm_GetFreeSRB
* Purpose : Get the first free SRB
* Inputs :
* Return : NULL or a free SCSI Request block
* ------------------------------------------------------------
*/
struct trm_scsi_req_q *
trm_GetFreeSRB(struct trm_softc *sc)
{
struct trm_scsi_req_q *pSRB;
/* ASSUME we are called from inside a splbio()/splx() region */
pSRB = TAILQ_FIRST(&sc->freeSRB);
if (pSRB != NULL)
TAILQ_REMOVE(&sc->freeSRB, pSRB, link);
#ifdef TRM_DEBUG0
printf("%s: trm_GetFreeSRB. pSRB = %p, next pSRB = %p\n",
sc->sc_device.dv_xname, pSRB, TAILQ_FIRST(&sc->freeSRB));
#endif
return pSRB;
}
/*
* ------------------------------------------------------------
* Function : trm_RewaitSRB
* Purpose : Q back to pending Q
* Inputs : struct trm_dcb * -
* struct trm_scsi_req_q * -
* ------------------------------------------------------------
*/
void
trm_RewaitSRB(struct trm_softc *sc, struct trm_scsi_req_q *pSRB)
{
int intflag;
intflag = splbio();
if ((pSRB->SRBFlag & TRM_ON_WAITING_SRB) != 0) {
pSRB->SRBFlag &= ~TRM_ON_WAITING_SRB;
TAILQ_REMOVE(&sc->waitingSRB, pSRB, link);
}
if ((pSRB->SRBFlag & TRM_ON_GOING_SRB) != 0) {
pSRB->SRBFlag &= ~TRM_ON_GOING_SRB;
TAILQ_REMOVE(&sc->goingSRB, pSRB, link);
}
pSRB->SRBState = TRM_READY;
pSRB->TargetStatus = SCSI_OK;
pSRB->AdaptStatus = TRM_STATUS_GOOD;
pSRB->SRBFlag |= TRM_ON_WAITING_SRB;
TAILQ_INSERT_HEAD(&sc->waitingSRB, pSRB, link);
splx(intflag);
}
/*
* ------------------------------------------------------------
* Function : trm_StartWaitingSRB
* Purpose : If there is no active DCB then run robin through
* the DCB's to find the next waiting SRB
* and move it to the going list.
* Inputs : struct trm_softc * -
* ------------------------------------------------------------
*/
void
trm_StartWaitingSRB(struct trm_softc *sc)
{
struct trm_scsi_req_q *pSRB, *next;
int intflag;
intflag = splbio();
if ((sc->pActiveDCB != NULL) ||
(TAILQ_EMPTY(&sc->waitingSRB)) ||
(sc->sc_Flag & (RESET_DETECT | RESET_DONE | RESET_DEV)) != 0)
return;
for (pSRB = TAILQ_FIRST(&sc->waitingSRB); pSRB != NULL; pSRB = next) {
next = TAILQ_NEXT(pSRB, link);
if (trm_StartSRB(sc, pSRB) == 0) {
pSRB->SRBFlag &= ~TRM_ON_WAITING_SRB;
TAILQ_REMOVE(&sc->waitingSRB, pSRB, link);
pSRB->SRBFlag |= TRM_ON_GOING_SRB;
TAILQ_INSERT_TAIL(&sc->goingSRB, pSRB, link);
break;
}
}
splx(intflag);
}
/*
* ------------------------------------------------------------
* Function : trm_scsi_cmd
* Purpose : enqueues a SCSI command
* Inputs :
* Call By : GENERIC SCSI driver
* ------------------------------------------------------------
*/
int
trm_scsi_cmd(struct scsi_xfer *xs)
{
struct trm_scsi_req_q *pSRB;
bus_space_handle_t ioh;
struct trm_softc *sc;
bus_space_tag_t iot;
struct trm_dcb *pDCB;
u_int8_t target, lun;
int i, error, intflag, xferflags;
target = xs->sc_link->target;
lun = xs->sc_link->lun;
sc = (struct trm_softc *)xs->sc_link->adapter_softc;
ioh = sc->sc_iohandle;
iot = sc->sc_iotag;
#ifdef TRM_DEBUG0
if ((xs->flags & SCSI_POLL) != 0)
printf("%s: trm_scsi_cmd. sc = %p, xs = %p, targ/lun = %d/%d opcode = 0x%02x\n",
sc->sc_device.dv_xname, sc, xs, target, lun, xs->cmd->opcode);
#endif
if (target >= TRM_MAX_TARGETS) {
printf("%s: target=%d >= %d\n",
sc->sc_device.dv_xname, target, TRM_MAX_TARGETS);
xs->error = XS_DRIVER_STUFFUP;
return COMPLETE;
}
if (lun >= TRM_MAX_LUNS) {
printf("%s: lun=%d >= %d\n",
sc->sc_device.dv_xname, lun, TRM_MAX_LUNS);
xs->error = XS_DRIVER_STUFFUP;
return COMPLETE;
}
pDCB = sc->pDCB[target][lun];
if (pDCB == NULL) {
/* Removed as a result of INQUIRY proving no device present */
xs->error = XS_DRIVER_STUFFUP;
return COMPLETE;
}
xferflags = xs->flags;
if (xferflags & SCSI_RESET) {
#ifdef TRM_DEBUG0
printf("%s: trm_reset\n", sc->sc_device.dv_xname);
#endif
trm_reset(sc);
xs->error = XS_NOERROR;
return COMPLETE;
}
if (xferflags & ITSDONE) {
#ifdef TRM_DEBUG0
printf("%s: Is it done?\n", sc->sc_device.dv_xname);
#endif
xs->flags &= ~ITSDONE;
}
xs->error = XS_NOERROR;
xs->status = SCSI_OK;
xs->resid = 0;
intflag = splbio();
pSRB = trm_GetFreeSRB(sc);
if (pSRB == NULL) {
splx(intflag);
return TRY_AGAIN_LATER;
}
/*
* BuildSRB(pSRB,pDCB);
*/
if (xs->datalen != 0) {
#ifdef TRM_DEBUG0
printf("%s: xs->datalen=%x\n", sc->sc_device.dv_xname,
(u_int32_t)xs->datalen);
printf("%s: sc->sc_dmatag=0x%x\n", sc->sc_device.dv_xname,
(u_int32_t)sc->sc_dmatag);
printf("%s: pSRB->dmamapxfer=0x%x\n", sc->sc_device.dv_xname,
(u_int32_t)pSRB->dmamapxfer);
printf("%s: xs->data=0x%x\n", sc->sc_device.dv_xname,
(u_int32_t)xs->data);
#endif
if ((error = bus_dmamap_load(sc->sc_dmatag, pSRB->dmamapxfer,
xs->data, xs->datalen, NULL,
(xferflags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT :
BUS_DMA_WAITOK)) != 0) {
printf("%s: DMA transfer map unable to load, error = %d\n"
, sc->sc_device.dv_xname, error);
xs->error = XS_DRIVER_STUFFUP;
/*
* free SRB
*/
TAILQ_INSERT_HEAD(&sc->freeSRB, pSRB, link);
splx(intflag);
return COMPLETE;
}
bus_dmamap_sync(sc->sc_dmatag, pSRB->dmamapxfer,
0, pSRB->dmamapxfer->dm_mapsize,
(xferflags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
/*
* Set up the scatter gather list
*/
for (i = 0; i < pSRB->dmamapxfer->dm_nsegs; i++) {
pSRB->SegmentX[i].address = pSRB->dmamapxfer->dm_segs[i].ds_addr;
pSRB->SegmentX[i].length = pSRB->dmamapxfer->dm_segs[i].ds_len;
}
pSRB->SRBTotalXferLength = xs->datalen;
pSRB->SRBSGCount = pSRB->dmamapxfer->dm_nsegs;
}
pSRB->pSRBDCB = pDCB;
pSRB->xs = xs;
pSRB->ScsiCmdLen = xs->cmdlen;
memcpy(pSRB->CmdBlock, xs->cmd, xs->cmdlen);
splx (intflag);
timeout_set(&xs->stimeout, trm_timeout, pSRB);
intflag = splbio();
pSRB->SRBFlag |= TRM_ON_WAITING_SRB;
TAILQ_INSERT_TAIL(&sc->waitingSRB, pSRB, link);
trm_StartWaitingSRB(sc);
if ((xferflags & SCSI_POLL) == 0) {
timeout_add(&xs->stimeout, (xs->timeout * hz) / 1000);
splx(intflag);
return SUCCESSFULLY_QUEUED;
}
while ((--xs->timeout > 0) && ((xs->flags & ITSDONE) == 0)) {
trm_Interrupt(sc);
DELAY(1000);
}
if (xs->timeout == 0)
trm_timeout(pSRB);
splx(intflag);
return COMPLETE;
}
/*
* ------------------------------------------------------------
* Function : trm_ResetAllDevParam
* Purpose :
* Inputs : struct trm_softc *
* ------------------------------------------------------------
*/
void
trm_ResetAllDevParam(struct trm_softc *sc)
{
struct trm_adapter_nvram *pEEpromBuf;
int target, quirks;
pEEpromBuf = &trm_eepromBuf[sc->sc_AdapterUnit];
for (target = 0; target < TRM_MAX_TARGETS; target++) {
if (target == sc->sc_AdaptSCSIID)
continue;
if ((sc->pDCB[target][0]->DCBFlag & TRM_QUIRKS_VALID) == 0)
quirks = SDEV_NOWIDE | SDEV_NOSYNC | SDEV_NOTAGS;
else
quirks = sc->pDCB[target][0]->sc_link->quirks;
trm_ResetDevParam(sc, sc->pDCB[target][0], quirks);
}
}
/*
* ------------------------------------------------------------
* Function : trm_ResetDevParam
* Purpose :
* Inputs :
* ------------------------------------------------------------
*/
void
trm_ResetDevParam(struct trm_softc *sc, struct trm_dcb *pDCB, u_int8_t quirks)
{
struct trm_adapter_nvram *pEEpromBuf = &trm_eepromBuf[sc->sc_AdapterUnit];
u_int8_t PeriodIndex;
const int target = pDCB->target;
pDCB->DCBFlag &= TRM_QUIRKS_VALID;
pDCB->DCBFlag |= (TRM_WIDE_NEGO_ENABLE | TRM_SYNC_NEGO_ENABLE);
pDCB->SyncPeriod = 0;
pDCB->SyncOffset = 0;
pDCB->MaxNegoPeriod = 0;
pDCB->DevMode = pEEpromBuf->NvramTarget[target].NvmTarCfg0;
pDCB->IdentifyMsg = MSG_IDENTIFY(pDCB->lun, ((pDCB->DevMode & TRM_DISCONNECT) != 0));
if (((quirks & SDEV_NOWIDE) == 0) &&
(pDCB->DevMode & TRM_WIDE) &&
((sc->sc_config & HCC_WIDE_CARD) != 0))
pDCB->DCBFlag |= TRM_WIDE_NEGO_16BIT;
if (((quirks & SDEV_NOSYNC) == 0) &&
((pDCB->DevMode & TRM_SYNC) != 0)) {
PeriodIndex = pEEpromBuf->NvramTarget[target].NvmTarPeriod & 0x07;
pDCB->MaxNegoPeriod = trm_clock_period[PeriodIndex];
}
if (((quirks & SDEV_NOTAGS) == 0) &&
((pDCB->DevMode & TRM_TAG_QUEUING) != 0) &&
((pDCB->DevMode & TRM_DISCONNECT) != 0))
/* TODO XXXX: Every device(lun) gets to queue TagMaxNum commands? */
pDCB->DCBFlag |= TRM_USE_TAG_QUEUING;
trm_SetXferParams(sc, pDCB, 0);
}
/*
* ------------------------------------------------------------
* Function : trm_RecoverSRB
* Purpose : Moves all SRBs from Going to Waiting for all the Link DCBs
* Inputs : struct trm_softc * -
* ------------------------------------------------------------
*/
void
trm_RecoverSRB(struct trm_softc *sc)
{
struct trm_scsi_req_q *pSRB;
/* ASSUME we are inside splbio()/splx() */
while ((pSRB = TAILQ_FIRST(&sc->goingSRB)) != NULL) {
pSRB->SRBFlag &= ~TRM_ON_GOING_SRB;
TAILQ_REMOVE(&sc->goingSRB, pSRB, link);
pSRB->SRBFlag |= TRM_ON_WAITING_SRB;
TAILQ_INSERT_HEAD(&sc->waitingSRB, pSRB, link);
}
}
/*
* ------------------------------------------------------------
* Function : trm_reset
* Purpose : perform a hard reset on the SCSI bus (and TRM_S1040 chip).
* Inputs :
* ------------------------------------------------------------
*/
void
trm_reset (struct trm_softc *sc)
{
const bus_space_handle_t ioh = sc->sc_iohandle;
const bus_space_tag_t iot = sc->sc_iotag;
int i, intflag;
#ifdef TRM_DEBUG0
printf("%s: trm_reset", sc->sc_device.dv_xname);
#endif
intflag = splbio();
bus_space_write_1(iot, ioh, TRM_S1040_DMA_INTEN, 0);
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_INTEN, 0);
trm_ResetSCSIBus(sc);
for (i = 0; i < 500; i++)
DELAY(1000);
/*
* Enable all SCSI interrupts except EN_SCAM
*/
bus_space_write_1(iot, ioh,
TRM_S1040_SCSI_INTEN,
(EN_SELECT | EN_SELTIMEOUT | EN_DISCONNECT | EN_RESELECTED |
EN_SCSIRESET | EN_BUSSERVICE | EN_CMDDONE));
/*
* Enable DMA interrupt
*/
bus_space_write_1(iot, ioh, TRM_S1040_DMA_INTEN, EN_SCSIINTR);
/*
* Clear DMA FIFO
*/
bus_space_write_1(iot, ioh, TRM_S1040_DMA_CONTROL, CLRXFIFO);
/*
* Clear SCSI FIFO
*/
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_CLRFIFO);
trm_ResetAllDevParam(sc);
trm_GoingSRB_Done(sc);
sc->pActiveDCB = NULL;
/*
* RESET_DETECT, RESET_DONE, RESET_DEV
*/
sc->sc_Flag = 0;
trm_StartWaitingSRB(sc);
splx(intflag);
}
/*
* ------------------------------------------------------------
* Function : trm_timeout
* Purpose : Prints a timeout message and aborts the timed out SCSI request
* Inputs : void * - A struct trm_scsi_req_q * structure pointer
* ------------------------------------------------------------
*/
void
trm_timeout(void *arg1)
{
struct trm_scsi_req_q *pSRB;
struct scsi_xfer *xs;
struct trm_softc *sc;
pSRB = (struct trm_scsi_req_q *)arg1;
xs = pSRB->xs;
if (xs != NULL) {
sc = xs->sc_link->adapter_softc;
sc_print_addr(xs->sc_link);
printf("%s: SCSI OpCode 0x%02x for target %d lun %d timed out\n",
sc->sc_device.dv_xname, xs->cmd->opcode,
xs->sc_link->target, xs->sc_link->lun);
pSRB->SRBFlag |= TRM_SCSI_TIMED_OUT;
trm_FinishSRB(sc, pSRB);
trm_StartWaitingSRB(sc);
}
#ifdef TRM_DEBUG0
else
printf("%s: trm_timeout called with xs == NULL\n",
sc->sc_device.dv_xname);
#endif
}
/*
* ------------------------------------------------------------
* Function : trm_StartSRB
* Purpose : Send the commands in the SRB to the device
* Inputs : struct trm_softc * -
* struct trm_scsi_req_q * -
* Return : 0 - SCSI processor is unoccupied
* 1 - SCSI processor is occupied with an SRB
* ------------------------------------------------------------
*/
int
trm_StartSRB(struct trm_softc *sc, struct trm_scsi_req_q *pSRB)
{
const bus_space_handle_t ioh = sc->sc_iohandle;
const bus_space_tag_t iot = sc->sc_iotag;
struct trm_dcb *pDCB = pSRB->pSRBDCB;
u_int32_t tag_mask;
u_int8_t tag_id, scsicommand;
#ifdef TRM_DEBUG0
printf("%s: trm_StartSRB. sc = %p, pDCB = %p, pSRB = %p\n",
sc->sc_device.dv_xname, sc, pDCB, pSRB);
#endif
/*
* If the queue is full or the SCSI processor has a pending interrupt
* then try again later.
*/
if ((pDCB->DCBFlag & TRM_QUEUE_FULL) || (bus_space_read_2(iot, ioh,
TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT))
return (1);
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_HOSTID, sc->sc_AdaptSCSIID);
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_TARGETID, pDCB->target);
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_SYNC, pDCB->SyncPeriod);
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_OFFSET, pDCB->SyncOffset);
if ((sc->pDCB[pDCB->target][0]->sc_link != NULL) &&
((sc->pDCB[pDCB->target][0]->DCBFlag & TRM_QUIRKS_VALID) == 0)) {
sc->pDCB[pDCB->target][0]->DCBFlag |= TRM_QUIRKS_VALID;
trm_ResetDevParam(sc, sc->pDCB[pDCB->target][0], sc->pDCB[pDCB->target][0]->sc_link->quirks);
}
/*
* Flush FIFO
*/
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_CLRFIFO);
sc->MsgCnt = 1;
sc->MsgBuf[0] = pDCB->IdentifyMsg;
if (((pSRB->xs->flags & SCSI_POLL) != 0) ||
(pSRB->CmdBlock[0] == INQUIRY) ||
(pSRB->CmdBlock[0] == REQUEST_SENSE))
sc->MsgBuf[0] &= ~MSG_IDENTIFY_DISCFLAG;
scsicommand = SCMD_SEL_ATN;
if ((pDCB->DCBFlag & (TRM_WIDE_NEGO_ENABLE | TRM_SYNC_NEGO_ENABLE)) != 0) {
scsicommand = SCMD_SEL_ATNSTOP;
pSRB->SRBState = TRM_MSGOUT;
} else if ((pDCB->DCBFlag & TRM_USE_TAG_QUEUING) == 0) {
pDCB->DCBFlag |= TRM_QUEUE_FULL;
} else if ((sc->MsgBuf[0] & MSG_IDENTIFY_DISCFLAG) != 0) {
if (pSRB->TagNumber == TRM_NO_TAG) {
for (tag_id=1, tag_mask=2; tag_id < 32; tag_id++, tag_mask <<= 1)
if ((tag_mask & pDCB->TagMask) == 0) {
pDCB->TagMask |= tag_mask;
pSRB->TagNumber = tag_id;
break;
}
if (tag_id >= 32) {
pDCB->DCBFlag |= TRM_QUEUE_FULL;
sc->MsgCnt = 0;
return 1;
}
}
/* TODO XXXX: Should send ORDERED_Q_TAG if metadata (non-block) i/o!? */
sc->MsgBuf[sc->MsgCnt++] = MSG_SIMPLE_Q_TAG;
sc->MsgBuf[sc->MsgCnt++] = pSRB->TagNumber;
scsicommand = SCMD_SEL_ATN3;
}
pSRB->SRBState = TRM_START;
pSRB->ScsiPhase = PH_BUS_FREE; /* SCSI bus free Phase */
sc->pActiveDCB = pDCB;
pDCB->pActiveSRB = pSRB;
if (sc->MsgCnt > 0) {
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_FIFO, sc->MsgBuf[0]);
if (sc->MsgCnt > 1) {
DELAY(30);
bus_space_write_multi_1(iot, ioh, TRM_S1040_SCSI_FIFO, &sc->MsgBuf[1], sc->MsgCnt - 1);
}
sc->MsgCnt = 0;
}
/*
* it's important for atn stop
*/
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_DATALATCH | DO_HWRESELECT);
/*
* SCSI command
*/
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_COMMAND, scsicommand);
return 0;
}
/*
* ------------------------------------------------------------
* Function : trm_Interrupt
* Purpose : Catch an interrupt from the adapter
* Process pending device interrupts.
* Inputs : void * - struct trm_softc * structure pointer
* ------------------------------------------------------------
*/
int
trm_Interrupt(void *vsc)
{
void (*stateV)(struct trm_softc *, struct trm_scsi_req_q *, u_int8_t *);
struct trm_scsi_req_q *pSRB;
bus_space_handle_t ioh;
struct trm_softc *sc = (struct trm_softc *)vsc;
bus_space_tag_t iot;
u_int16_t phase;
u_int8_t scsi_status, scsi_intstatus;
int intflag;
intflag = splbio();
if (sc == NULL) {
splx(intflag);
return 0;
}
ioh = sc->sc_iohandle;
iot = sc->sc_iotag;
scsi_status = bus_space_read_2(iot, ioh, TRM_S1040_SCSI_STATUS);
if (!(scsi_status & SCSIINTERRUPT)) {
splx(intflag);
return 0;
}
scsi_intstatus = bus_space_read_1(iot, ioh, TRM_S1040_SCSI_INTSTATUS);
#ifdef TRM_DEBUG0
printf("%s: trm_interrupt - scsi_status=0x%02x, scsi_intstatus=0x%02x\n",
sc->sc_device.dv_xname, scsi_status, scsi_intstatus);
#endif
if ((scsi_intstatus & (INT_SELTIMEOUT | INT_DISCONNECT)) != 0)
trm_Disconnect(sc);
else if ((scsi_intstatus & INT_RESELECTED) != 0)
trm_Reselect(sc);
else if ((scsi_intstatus & INT_SCSIRESET) != 0)
trm_ScsiRstDetect(sc);
else if ((sc->pActiveDCB != NULL) && ((scsi_intstatus & (INT_BUSSERVICE | INT_CMDDONE)) != 0)) {
pSRB = sc->pActiveDCB->pActiveSRB;
/*
* software sequential machine
*/
phase = (u_int16_t) pSRB->ScsiPhase; /* phase: */
/*
* 62037 or 62137
* call trm_SCSI_phase0[]... "phase entry"
* handle every phase before start transfer
*/
stateV = trm_SCSI_phase0[phase];
stateV(sc, pSRB, &scsi_status);
/*
* if any exception occurred
* scsi_status will be modified to bus free phase
* new scsi_status transfer out from previous stateV
*/
/*
* phase:0,1,2,3,4,5,6,7
*/
pSRB->ScsiPhase = scsi_status & PHASEMASK;
phase = (u_int16_t) scsi_status & PHASEMASK;
/*
* call trm_SCSI_phase1[]... "phase entry"
* handle every phase do transfer
*/
stateV = trm_SCSI_phase1[phase];
stateV(sc, pSRB, &scsi_status);
} else {
splx(intflag);
return 0;
}
splx(intflag);
return 1;
}
/*
* ------------------------------------------------------------
* Function : trm_MsgOutPhase0
* Purpose : Check the state machine before sending a message out
* Inputs : struct trm_softc * -
* struct trm_scsi_req_q * -
* u_int8_t * - scsi status, set to PH_BUS_FREE if not ready
* ------------------------------------------------------------
*/
void
trm_MsgOutPhase0(struct trm_softc *sc, struct trm_scsi_req_q *pSRB, u_int8_t *pscsi_status)
{
switch (pSRB->SRBState) {
case TRM_UNEXPECT_RESEL:
case TRM_ABORT_SENT:
*pscsi_status = PH_BUS_FREE; /* initial phase */
break;
default:
break;
}
}
/*
* ------------------------------------------------------------
* Function : trm_MsgOutPhase1
* Purpose : Write the message out to the bus
* Inputs : struct trm_softc * -
* struct trm_scsi_req_q * -
* u_int8_t * - unused
* ------------------------------------------------------------
*/
void
trm_MsgOutPhase1(struct trm_softc *sc, struct trm_scsi_req_q *pSRB, u_int8_t *pscsi_status)
{
const bus_space_handle_t ioh = sc->sc_iohandle;
const bus_space_tag_t iot = sc->sc_iotag;
struct trm_dcb *pDCB = sc->pActiveDCB;
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_CLRFIFO);
if ((pDCB->DCBFlag & TRM_WIDE_NEGO_ENABLE) != 0) {
/*
* WIDE DATA TRANSFER REQUEST code (03h)
*/
pDCB->DCBFlag &= ~TRM_WIDE_NEGO_ENABLE;
pDCB->DCBFlag |= TRM_DOING_WIDE_NEGO;
sc->MsgBuf[0] = pDCB->IdentifyMsg & ~MSG_IDENTIFY_DISCFLAG;
sc->MsgBuf[1] = MSG_EXTENDED;
sc->MsgBuf[2] = MSG_EXT_WDTR_LEN;
sc->MsgBuf[3] = MSG_EXT_WDTR;
if ((pDCB->DCBFlag & TRM_WIDE_NEGO_16BIT) == 0)
sc->MsgBuf[4] = MSG_EXT_WDTR_BUS_8_BIT;
else
sc->MsgBuf[4] = MSG_EXT_WDTR_BUS_16_BIT;
sc->MsgCnt = 5;
} else if ((pDCB->DCBFlag & TRM_SYNC_NEGO_ENABLE) != 0) {
pDCB->DCBFlag &= ~TRM_SYNC_NEGO_ENABLE;
pDCB->DCBFlag |= TRM_DOING_SYNC_NEGO;
sc->MsgCnt = 0;
if ((pDCB->DCBFlag & TRM_WIDE_NEGO_DONE) == 0)
sc->MsgBuf[sc->MsgCnt++] = pDCB->IdentifyMsg & ~MSG_IDENTIFY_DISCFLAG;
sc->MsgBuf[sc->MsgCnt++] = MSG_EXTENDED;
sc->MsgBuf[sc->MsgCnt++] = MSG_EXT_SDTR_LEN;
sc->MsgBuf[sc->MsgCnt++] = MSG_EXT_SDTR;
sc->MsgBuf[sc->MsgCnt++] = pDCB->MaxNegoPeriod;
if (pDCB->MaxNegoPeriod > 0)
sc->MsgBuf[sc->MsgCnt++] = TRM_MAX_SYNC_OFFSET;
else
sc->MsgBuf[sc->MsgCnt++] = 0;
}
if (sc->MsgCnt > 0) {
bus_space_write_multi_1(iot, ioh, TRM_S1040_SCSI_FIFO, &sc->MsgBuf[0], sc->MsgCnt);
if (sc->MsgBuf[0] == MSG_ABORT)
pSRB->SRBState = TRM_ABORT_SENT;
sc->MsgCnt = 0;
}
/*
* it's important for atn stop
*/
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
/*
* Transfer information out
*/
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT);
}
/*
* ------------------------------------------------------------
* Function : trm_CommandPhase1
* Purpose : Send commands to bus
* Inputs :
* ------------------------------------------------------------
*/
void
trm_CommandPhase1(struct trm_softc *sc, struct trm_scsi_req_q *pSRB, u_int8_t *pscsi_status)
{
const bus_space_handle_t ioh = sc->sc_iohandle;
const bus_space_tag_t iot = sc->sc_iotag;
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_CLRATN | DO_CLRFIFO);
bus_space_write_multi_1(iot, ioh, TRM_S1040_SCSI_FIFO, &pSRB->CmdBlock[0], pSRB->ScsiCmdLen);
pSRB->SRBState = TRM_COMMAND;
/*
* it's important for atn stop
*/
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
/*
* Transfer information out
*/
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT);
}
/*
* ------------------------------------------------------------
* Function : trm_DataOutPhase0
* Purpose : Ready for Data Out, clear FIFO
* Inputs : u_int8_t * - SCSI status, used but not set
* ------------------------------------------------------------
*/
void
trm_DataOutPhase0(struct trm_softc *sc, struct trm_scsi_req_q *pSRB, u_int8_t *pscsi_status)
{
const bus_space_handle_t ioh = sc->sc_iohandle;
const bus_space_tag_t iot = sc->sc_iotag;
struct SGentry *pseg;
struct trm_dcb *pDCB;
u_int32_t dLeftCounter, TempSRBXferredLength;
u_int16_t scsi_status;
u_int8_t TempDMAstatus, SGIndexTemp;
dLeftCounter = 0;
pDCB = pSRB->pSRBDCB;
scsi_status = *pscsi_status;
if (pSRB->SRBState != TRM_XFERPAD) {
if ((scsi_status & PARITYERROR) != 0)
pSRB->SRBFlag |= TRM_PARITY_ERROR;
if ((scsi_status & SCSIXFERDONE) == 0) {
/*
* when data transfer from DMA FIFO to SCSI FIFO
* if there was some data left in SCSI FIFO
*/
dLeftCounter = (u_int32_t)(bus_space_read_1(
iot, ioh, TRM_S1040_SCSI_FIFOCNT) & 0x1F);
if (pDCB->SyncPeriod & WIDE_SYNC) {
/*
* if WIDE scsi SCSI FIFOCNT unit is word
* so need to * 2
*/
dLeftCounter <<= 1;
}
}
/*
* calculate all the residue data that not yet transferred
* SCSI transfer counter + left in SCSI FIFO data
*
* .....TRM_S1040_SCSI_COUNTER (24bits)
* The counter always decrement by one for every SCSI byte
* transfer.
* .....TRM_S1040_SCSI_FIFOCNT ( 5bits)
* The counter is SCSI FIFO offset counter
*/
dLeftCounter += bus_space_read_4(iot, ioh,
TRM_S1040_SCSI_COUNTER);
if (dLeftCounter == 1) {
dLeftCounter = 0;
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL,
DO_CLRFIFO);
}
if (dLeftCounter == 0 ||
(scsi_status & SCSIXFERCNT_2_ZERO) != 0) {
TempDMAstatus = bus_space_read_1(iot,
ioh, TRM_S1040_DMA_STATUS);
while ((TempDMAstatus & DMAXFERCOMP) == 0) {
TempDMAstatus = bus_space_read_1(iot,
ioh, TRM_S1040_DMA_STATUS);
}
pSRB->SRBTotalXferLength = 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 (pSRB->SRBTotalXferLength != dLeftCounter) {
/*
* data that had transferred length
*/
TempSRBXferredLength = pSRB->SRBTotalXferLength
- dLeftCounter;
/*
* next time to be transferred length
*/
pSRB->SRBTotalXferLength = dLeftCounter;
/*
* parsing from last time disconnect SRBSGIndex
*/
pseg = &pSRB->SegmentX[pSRB->SRBSGIndex];
for (SGIndexTemp = pSRB->SRBSGIndex;
SGIndexTemp < pSRB->SRBSGCount;
SGIndexTemp++) {
/*
* find last time which SG transfer be
* disconnect
*/
if (TempSRBXferredLength >= pseg->length)
TempSRBXferredLength -= pseg->length;
else {
/*
* update last time disconnected
* SG list
*/
/*
* residue data length
*/
pseg->length -=
TempSRBXferredLength;
/*
* residue data pointer
*/
pseg->address +=
TempSRBXferredLength;
pSRB->SRBSGIndex = SGIndexTemp;
break;
}
pseg++;
}
}
}
}
bus_space_write_1(iot, ioh, TRM_S1040_DMA_CONTROL, STOPDMAXFER);
}
/*
* ------------------------------------------------------------
* Function : trm_DataOutPhase1
* Purpose : Transfers data out, calls trm_DataIO_transfer
* Inputs :
* ------------------------------------------------------------
*/
void
trm_DataOutPhase1(struct trm_softc *sc, struct trm_scsi_req_q *pSRB, u_int8_t *pscsi_status)
{
trm_DataIO_transfer(sc, pSRB, XFERDATAOUT);
}
/*
* ------------------------------------------------------------
* Function : trm_DataInPhase0
* Purpose : Prepare for reading data in from bus
* Inputs :
* ------------------------------------------------------------
*/
void
trm_DataInPhase0(struct trm_softc *sc, struct trm_scsi_req_q *pSRB, u_int8_t *pscsi_status)
{
const bus_space_handle_t ioh = sc->sc_iohandle;
const bus_space_tag_t iot = sc->sc_iotag;
struct SGentry *pseg;
u_int32_t TempSRBXferredLength, dLeftCounter;
u_int16_t scsi_status;
u_int8_t SGIndexTemp;
dLeftCounter = 0;
scsi_status = *pscsi_status;
if (pSRB->SRBState != TRM_XFERPAD) {
if ((scsi_status & PARITYERROR) != 0)
pSRB->SRBFlag |= TRM_PARITY_ERROR;
dLeftCounter += bus_space_read_4(iot, ioh,
TRM_S1040_SCSI_COUNTER);
if (dLeftCounter == 0 ||
(scsi_status & SCSIXFERCNT_2_ZERO) != 0) {
while ((bus_space_read_1(iot, ioh, TRM_S1040_DMA_STATUS) & DMAXFERCOMP) == 0)
;
pSRB->SRBTotalXferLength = 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 (pSRB->SRBTotalXferLength != dLeftCounter) {
/*
* data that had transferred length
*/
TempSRBXferredLength = pSRB->SRBTotalXferLength
- dLeftCounter;
/*
* next time to be transferred length
*/
pSRB->SRBTotalXferLength = dLeftCounter;
/*
* parsing from last time disconnect SRBSGIndex
*/
pseg = &pSRB->SegmentX[pSRB->SRBSGIndex];
for (SGIndexTemp = pSRB->SRBSGIndex;
SGIndexTemp < pSRB->SRBSGCount;
SGIndexTemp++) {
/*
* find last time which SG transfer be
* disconnect
*/
if (TempSRBXferredLength >=
pseg->length) {
TempSRBXferredLength -= pseg->length;
} else {
/*
* update last time disconnected
* SG list
*
* residue data length
*/
pseg->length -= TempSRBXferredLength;
/*
* residue data pointer
*/
pseg->address += TempSRBXferredLength;
pSRB->SRBSGIndex = SGIndexTemp;
break;
}
pseg++;
}
}
}
}
}
/*
* ------------------------------------------------------------
* Function : trm_DataInPhase1
* Purpose : Transfer data in from bus, calls trm_DataIO_transfer
* Inputs :
* ------------------------------------------------------------
*/
void
trm_DataInPhase1(struct trm_softc *sc, struct trm_scsi_req_q *pSRB, u_int8_t *pscsi_status)
{
trm_DataIO_transfer(sc, pSRB, XFERDATAIN);
}
/*
* ------------------------------------------------------------
* Function : trm_DataIO_transfer
* Purpose :
* Inputs :
* ------------------------------------------------------------
*/
void
trm_DataIO_transfer(struct trm_softc *sc, struct trm_scsi_req_q *pSRB, u_int16_t ioDir)
{
const bus_space_handle_t ioh = sc->sc_iohandle;
const bus_space_tag_t iot = sc->sc_iotag;
struct trm_dcb *pDCB = pSRB->pSRBDCB;
u_int8_t bval;
if (pSRB->SRBSGIndex < pSRB->SRBSGCount) {
if (pSRB->SRBTotalXferLength != 0) {
/*
* load what physical address of Scatter/Gather list
* table want to be transfer
*/
pSRB->SRBState = TRM_DATA_XFER;
bus_space_write_4(iot, ioh, TRM_S1040_DMA_XHIGHADDR, 0);
bus_space_write_4(iot, ioh,
TRM_S1040_DMA_XLOWADDR, (pSRB->SRBSGPhyAddr +
((u_int32_t)pSRB->SRBSGIndex << 3)));
/*
* load how many bytes in the Scatter/Gather list table
*/
bus_space_write_4(iot, ioh, TRM_S1040_DMA_XCNT,
((u_int32_t)(pSRB->SRBSGCount -
pSRB->SRBSGIndex) << 3));
/*
* load total transfer length (24bits,
* pSRB->SRBTotalXferLength) max value 16Mbyte
*/
bus_space_write_4(iot, ioh,
TRM_S1040_SCSI_COUNTER, pSRB->SRBTotalXferLength);
/*
* Start DMA transfer
*/
bus_space_write_2(iot,ioh,TRM_S1040_DMA_COMMAND, ioDir);
/* bus_space_write_2(iot, ioh,
TRM_S1040_DMA_CONTROL, STARTDMAXFER);*/
/*
* Set the transfer bus and direction
*/
bval = ioDir == XFERDATAOUT ? SCMD_DMA_OUT :SCMD_DMA_IN;
} else {
/*
* xfer pad
*/
if (pSRB->SRBSGCount)
pSRB->AdaptStatus = TRM_OVER_UNDER_RUN;
if (pDCB->SyncPeriod & WIDE_SYNC) {
bus_space_write_4(iot, ioh,
TRM_S1040_SCSI_COUNTER, 2);
} else {
bus_space_write_4(iot, ioh,
TRM_S1040_SCSI_COUNTER, 1);
}
if (ioDir == XFERDATAOUT) {
bus_space_write_2(iot,
ioh, TRM_S1040_SCSI_FIFO, 0);
} else {
bus_space_read_2(iot,
ioh, TRM_S1040_SCSI_FIFO);
}
pSRB->SRBState = TRM_XFERPAD;
/*
* Set the transfer bus and direction
*/
bval = ioDir == XFERDATAOUT ? SCMD_FIFO_OUT : SCMD_FIFO_IN;
}
/*
* it's important for atn stop
*/
bus_space_write_2(iot,ioh,TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
/*
* Tell the bus to do the transfer
*/
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_COMMAND, bval);
}
}
/*
* ------------------------------------------------------------
* Function : trm_StatusPhase0
* Purpose : Update Target Status with data from SCSI FIFO
* Inputs : u_int8_t * - Set to PH_BUS_FREE
* ------------------------------------------------------------
*/
void
trm_StatusPhase0(struct trm_softc *sc, struct trm_scsi_req_q *pSRB, u_int8_t *pscsi_status)
{
const bus_space_handle_t ioh = sc->sc_iohandle;
const bus_space_tag_t iot = sc->sc_iotag;
pSRB->TargetStatus = bus_space_read_1(iot, ioh, TRM_S1040_SCSI_FIFO);
pSRB->SRBState = TRM_COMPLETED;
/*
* initial phase
*/
*pscsi_status = PH_BUS_FREE;
/*
* it's important for atn stop
*/
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
/*
* Tell bus that the message was accepted
*/
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT);
}
/*
* ------------------------------------------------------------
* Function : trm_StatusPhase1
* Purpose : Clear FIFO of DMA and SCSI
* Inputs :
* ------------------------------------------------------------
*/
void
trm_StatusPhase1(struct trm_softc *sc, struct trm_scsi_req_q *pSRB, u_int8_t *pscsi_status)
{
const bus_space_handle_t ioh = sc->sc_iohandle;
const bus_space_tag_t iot = sc->sc_iotag;
if ((bus_space_read_2(iot, ioh, TRM_S1040_DMA_COMMAND) & 0x0001) != 0) {
if ((bus_space_read_1(iot, ioh, TRM_S1040_SCSI_FIFOCNT) & 0x40)
== 0) {
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL,
DO_CLRFIFO);
}
if ((bus_space_read_2(iot, ioh,
TRM_S1040_DMA_FIFOCNT) & 0x8000) == 0) {
bus_space_write_1(iot, ioh,
TRM_S1040_DMA_CONTROL, CLRXFIFO);
}
} else {
if ((bus_space_read_2(iot, ioh,
TRM_S1040_DMA_FIFOCNT) & 0x8000) == 0) {
bus_space_write_1(iot, ioh,
TRM_S1040_DMA_CONTROL, CLRXFIFO);
}
if ((bus_space_read_1(iot, ioh,
TRM_S1040_SCSI_FIFOCNT) & 0x40) == 0) {
bus_space_write_2(iot, ioh,
TRM_S1040_SCSI_CONTROL, DO_CLRFIFO);
}
}
pSRB->SRBState = TRM_STATUS;
/*
* it's important for atn stop
*/
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
/*
* Tell the bus that the command is complete
*/
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_COMMAND, SCMD_COMP);
}
/*
* ------------------------------------------------------------
* Function : trm_MsgInPhase0
* Purpose :
* Inputs :
*
* extended message codes:
* code description
* ---- -----------
* 02h Reserved
* 00h MODIFY DATA POINTER
* 01h SYNCHRONOUS DATA TRANSFER REQUEST
* 03h WIDE DATA TRANSFER REQUEST
* 04h - 7Fh Reserved
* 80h - FFh Vendor specific
*
* ------------------------------------------------------------
*/
void
trm_MsgInPhase0(struct trm_softc *sc, struct trm_scsi_req_q *pSRB, u_int8_t *pscsi_status)
{
const bus_space_handle_t ioh = sc->sc_iohandle;
const bus_space_tag_t iot = sc->sc_iotag;
struct trm_dcb *pDCB;
u_int8_t message_in_code, bIndex, message_in_tag_id;
pDCB = sc->pActiveDCB;
message_in_code = bus_space_read_1(iot, ioh, TRM_S1040_SCSI_FIFO);
if (pSRB->SRBState != TRM_EXTEND_MSGIN) {
switch (message_in_code) {
case MSG_DISCONNECT:
pSRB->SRBState = TRM_DISCONNECTED;
break;
case MSG_EXTENDED:
case MSG_SIMPLE_Q_TAG:
case MSG_HEAD_OF_Q_TAG:
case MSG_ORDERED_Q_TAG:
pSRB->SRBState = TRM_EXTEND_MSGIN;
/*
* extended message (01h)
*/
bzero(&sc->MsgBuf[0], sizeof(sc->MsgBuf));
sc->MsgBuf[0] = message_in_code;
sc->MsgCnt = 1;
/*
* extended message length (n)
*/
break;
case MSG_MESSAGE_REJECT:
/*
* Reject message
*/
if ((pDCB->DCBFlag & TRM_DOING_WIDE_NEGO) != 0) {
/*
* do wide nego reject
*/
pDCB = pSRB->pSRBDCB;
pDCB->DCBFlag &= ~TRM_DOING_WIDE_NEGO;
pDCB->DCBFlag |= TRM_WIDE_NEGO_DONE;
if ((pDCB->DCBFlag & TRM_SYNC_NEGO_ENABLE) != 0) {
/*
* Set ATN, in case ATN was clear
*/
pSRB->SRBState = TRM_MSGOUT;
bus_space_write_2(iot, ioh,
TRM_S1040_SCSI_CONTROL, DO_SETATN);
} else {
/*
* Clear ATN
*/
bus_space_write_2(iot, ioh,
TRM_S1040_SCSI_CONTROL, DO_CLRATN);
}
} else if ((pDCB->DCBFlag & TRM_DOING_SYNC_NEGO) != 0) {
/*
* do sync nego reject
*/
pDCB = pSRB->pSRBDCB;
pDCB->DCBFlag &= ~TRM_DOING_SYNC_NEGO;
pDCB->SyncPeriod = 0;
pDCB->SyncOffset = 0;
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_CLRATN);
goto re_prog;
}
break;
case MSG_IGN_WIDE_RESIDUE:
bus_space_write_4(iot, ioh, TRM_S1040_SCSI_COUNTER, 1);
bus_space_read_1(iot, ioh, TRM_S1040_SCSI_FIFO);
break;
default:
break;
}
} else {
/*
* We are collecting an extended message. Save the latest byte and then
* check to see if the message is complete. If so, process it.
*/
sc->MsgBuf[sc->MsgCnt++] = message_in_code;
#ifdef TRM_DEBUG0
printf("%s: sc->MsgBuf = 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
sc->sc_device.dv_xname,
sc->MsgBuf[0], sc->MsgBuf[1], sc->MsgBuf[2], sc->MsgBuf[3], sc->MsgBuf[4], sc->MsgBuf[5] );
#endif
switch (sc->MsgBuf[0]) {
case MSG_SIMPLE_Q_TAG:
case MSG_HEAD_OF_Q_TAG:
case MSG_ORDERED_Q_TAG:
if (sc->MsgCnt == 2) {
pSRB->SRBState = TRM_FREE;
message_in_tag_id = sc->MsgBuf[1];
sc->MsgCnt = 0;
TAILQ_FOREACH(pSRB, &sc->goingSRB, link) {
if ((pSRB->pSRBDCB == pDCB) && (pSRB->TagNumber == message_in_tag_id))
break;
}
if ((pSRB != NULL) && (pSRB->SRBState == TRM_DISCONNECTED)) {
pDCB->pActiveSRB = pSRB;
pSRB->SRBState = TRM_DATA_XFER;
} else {
pSRB = &sc->SRB[0];
pSRB->SRBState = TRM_UNEXPECT_RESEL;
pDCB->pActiveSRB = pSRB;
trm_EnableMsgOut(sc, MSG_ABORT_TAG);
}
}
break;
case MSG_EXTENDED:
/* TODO XXXX: Correctly handling target initiated negotiations? */
if ((sc->MsgBuf[2] == MSG_EXT_WDTR) && (sc->MsgCnt == 4)) {
/*
* ======================================
* 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
*/
pSRB->SRBState = TRM_FREE;
pDCB->DCBFlag &= ~(TRM_WIDE_NEGO_ENABLE | TRM_DOING_WIDE_NEGO);
if (sc->MsgBuf[1] != MSG_EXT_WDTR_LEN)
goto reject_offer;
switch (sc->MsgBuf[3]) {
case MSG_EXT_WDTR_BUS_32_BIT:
if ((pDCB->DCBFlag & TRM_WIDE_NEGO_16BIT) == 0)
sc->MsgBuf[3] = MSG_EXT_WDTR_BUS_8_BIT;
else
sc->MsgBuf[3] = MSG_EXT_WDTR_BUS_16_BIT;
break;
case MSG_EXT_WDTR_BUS_16_BIT:
if ((pDCB->DCBFlag & TRM_WIDE_NEGO_16BIT) == 0) {
sc->MsgBuf[3] = MSG_EXT_WDTR_BUS_8_BIT;
break;
}
pDCB->SyncPeriod |= WIDE_SYNC;
/* FALL THROUGH == ACCEPT OFFER */
case MSG_EXT_WDTR_BUS_8_BIT:
pSRB->SRBState = TRM_MSGOUT;
pDCB->DCBFlag |= (TRM_SYNC_NEGO_ENABLE | TRM_WIDE_NEGO_DONE);
if (pDCB->MaxNegoPeriod == 0) {
pDCB->SyncPeriod = 0;
pDCB->SyncOffset = 0;
goto re_prog;
}
break;
default:
pDCB->DCBFlag &= ~TRM_WIDE_NEGO_ENABLE;
pDCB->DCBFlag |= TRM_WIDE_NEGO_DONE;
reject_offer:
sc->MsgCnt = 1;
sc->MsgBuf[0] = MSG_MESSAGE_REJECT;
break;
}
/* Echo accepted offer, or send revised offer */
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_SETATN);
} else if ((sc->MsgBuf[2] == MSG_EXT_SDTR) && (sc->MsgCnt == 5)) {
/*
* =================================
* 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
*/
pSRB->SRBState = TRM_FREE;
pDCB->DCBFlag &= ~(TRM_SYNC_NEGO_ENABLE | TRM_DOING_SYNC_NEGO);
if (sc->MsgBuf[1] != MSG_EXT_SDTR_LEN)
goto reject_offer;
if ((sc->MsgBuf[3] == 0) || (sc->MsgBuf[4] == 0)) {
/*
* Asynchronous transfers
*/
pDCB->SyncPeriod = 0;
pDCB->SyncOffset = 0;
} else {
/*
* Synchronous transfers
*/
/*
* REQ/ACK offset
*/
pDCB->SyncOffset = sc->MsgBuf[4];
for (bIndex = 0; bIndex < 7; bIndex++)
if (sc->MsgBuf[3] <= trm_clock_period[bIndex])
break;
pDCB->SyncPeriod |= (bIndex | ALT_SYNC);
}
re_prog: /*
* program SCSI control register
*/
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_SYNC, pDCB->SyncPeriod);
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_OFFSET, pDCB->SyncOffset);
trm_SetXferParams(sc, pDCB, (pDCB->DCBFlag & TRM_QUIRKS_VALID));
}
break;
default:
break;
}
}
/*
* initial phase
*/
*pscsi_status = PH_BUS_FREE;
/*
* it's important for atn stop
*/
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
/*
* Tell bus that the message was accepted
*/
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT);
}
/*
* ------------------------------------------------------------
* Function : trm_MsgInPhase1
* Purpose : Clear the FIFO
* Inputs :
* ------------------------------------------------------------
*/
void
trm_MsgInPhase1(struct trm_softc *sc, struct trm_scsi_req_q *pSRB, u_int8_t *pscsi_status)
{
const bus_space_handle_t ioh = sc->sc_iohandle;
const bus_space_tag_t iot = sc->sc_iotag;
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_CLRFIFO);
bus_space_write_4(iot, ioh, TRM_S1040_SCSI_COUNTER, 1);
/*
* it's important for atn stop
*/
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
/*
* SCSI command
*/
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_IN);
}
/*
* ------------------------------------------------------------
* Function : trm_Nop
* Purpose : EMPTY
* Inputs :
* ------------------------------------------------------------
*/
void
trm_Nop(struct trm_softc *sc, struct trm_scsi_req_q *pSRB, u_int8_t *pscsi_status)
{
}
/*
* ------------------------------------------------------------
* Function : trm_SetXferParams
* Purpose : Set the Sync period, offset and mode for each device that has
* the same target as the given one (struct trm_dcb *)
* Inputs :
* ------------------------------------------------------------
*/
void
trm_SetXferParams(struct trm_softc *sc, struct trm_dcb *pDCB, int print_info)
{
struct trm_dcb *pDCBTemp;
int lun, target;
/*
* set all lun device's period, offset
*/
#ifdef TRM_DEBUG0
printf("%s: trm_SetXferParams\n", sc->sc_device.dv_xname);
#endif
target = pDCB->target;
for(lun = 0; lun < TRM_MAX_LUNS; lun++) {
pDCBTemp = sc->pDCB[target][lun];
if (pDCBTemp != NULL) {
pDCBTemp->DevMode = pDCB->DevMode;
pDCBTemp->MaxNegoPeriod = pDCB->MaxNegoPeriod;
pDCBTemp->SyncPeriod = pDCB->SyncPeriod;
pDCBTemp->SyncOffset = pDCB->SyncOffset;
pDCBTemp->DCBFlag = pDCB->DCBFlag;
}
}
if (print_info)
trm_print_info(sc, pDCB);
}
/*
* ------------------------------------------------------------
* Function : trm_Disconnect
* Purpose :
* Inputs :
*
* ---SCSI bus phase
* PH_DATA_OUT 0x00 Data out phase
* PH_DATA_IN 0x01 Data in phase
* PH_COMMAND 0x02 Command phase
* PH_STATUS 0x03 Status phase
* PH_BUS_FREE 0x04 Invalid phase used as bus free
* PH_BUS_FREE 0x05 Invalid phase used as bus free
* PH_MSG_OUT 0x06 Message out phase
* PH_MSG_IN 0x07 Message in phase
* ------------------------------------------------------------
*/
void
trm_Disconnect(struct trm_softc *sc)
{
const bus_space_handle_t ioh = sc->sc_iohandle;
struct trm_scsi_req_q *pSRB, *pNextSRB;
const bus_space_tag_t iot = sc->sc_iotag;
struct trm_dcb *pDCB;
int j;
#ifdef TRM_DEBUG0
printf("%s: trm_Disconnect\n", sc->sc_device.dv_xname);
#endif
pDCB = sc->pActiveDCB;
if (pDCB == NULL) {
/* TODO: Why use a loop? Why not use DELAY(400)? */
for(j = 400; j > 0; --j)
DELAY(1); /* 1 msec */
bus_space_write_2(iot, ioh,
TRM_S1040_SCSI_CONTROL, (DO_CLRFIFO | DO_HWRESELECT));
return;
}
pSRB = pDCB->pActiveSRB;
sc->pActiveDCB = NULL;
pSRB->ScsiPhase = PH_BUS_FREE; /* SCSI bus free Phase */
bus_space_write_2(iot, ioh,
TRM_S1040_SCSI_CONTROL, (DO_CLRFIFO | DO_HWRESELECT));
DELAY(100);
switch (pSRB->SRBState) {
case TRM_UNEXPECT_RESEL:
pSRB->SRBState = TRM_FREE;
break;
case TRM_ABORT_SENT:
pSRB = TAILQ_FIRST(&sc->goingSRB);
while (pSRB != NULL) {
/*
* Need to save pNextSRB because trm_FinishSRB() puts
* pSRB in freeSRB queue, and thus its links no longer
* point to members of the goingSRB queue. This is why
* TAILQ_FOREACH() will not work for this traversal.
*/
pNextSRB = TAILQ_NEXT(pSRB, link);
if (pSRB->pSRBDCB == pDCB) {
/* TODO XXXX: Is TIMED_OUT the best state to report? */
pSRB->SRBFlag |= TRM_SCSI_TIMED_OUT;
trm_FinishSRB(sc, pSRB);
}
pSRB = pNextSRB;
}
break;
case TRM_START:
case TRM_MSGOUT:
/*
* Selection time out
*/
/* If not polling just keep trying until xs->stimeout expires */
if ((pSRB->xs->flags & SCSI_POLL) == 0) {
trm_RewaitSRB(sc, pSRB);
} else {
pSRB->TargetStatus = TRM_SCSI_SELECT_TIMEOUT;
goto disc1;
}
break;
case TRM_COMPLETED:
disc1:
/*
* TRM_COMPLETED - remove id from mask of active tags
*/
pDCB->pActiveSRB = NULL;
trm_FinishSRB(sc, pSRB);
break;
default:
break;
}
trm_StartWaitingSRB(sc);
}
/*
* ------------------------------------------------------------
* Function : trm_Reselect
* Purpose :
* Inputs :
* ------------------------------------------------------------
*/
void
trm_Reselect(struct trm_softc *sc)
{
const bus_space_handle_t ioh = sc->sc_iohandle;
const bus_space_tag_t iot = sc->sc_iotag;
struct trm_scsi_req_q *pSRB;
struct trm_dcb *pDCB;
u_int16_t RselTarLunId;
u_int8_t target, lun;
#ifdef TRM_DEBUG0
printf("%s: trm_Reselect\n", sc->sc_device.dv_xname);
#endif
pDCB = sc->pActiveDCB;
if (pDCB != NULL) {
/*
* Arbitration lost but Reselection win
*/
pSRB = pDCB->pActiveSRB;
trm_RewaitSRB(sc, pSRB);
}
/*
* Read Reselected Target Id and LUN
*/
RselTarLunId = bus_space_read_2(iot, ioh, TRM_S1040_SCSI_TARGETID) & 0x1FFF;
/* TODO XXXX: Make endian independent! */
target = RselTarLunId & 0xff;
lun = (RselTarLunId >> 8) & 0xff;
#ifdef TRM_DEBUG0
printf("%s: reselect - target = %d, lun = %d\n",
sc->sc_device.dv_xname, target, lun);
#endif
if ((target < TRM_MAX_TARGETS) && (lun < TRM_MAX_LUNS))
pDCB = sc->pDCB[target][lun];
else
pDCB = NULL;
if (pDCB == NULL)
printf("%s: reselect - target = %d, lun = %d not found\n",
sc->sc_device.dv_xname, target, lun);
sc->pActiveDCB = pDCB;
/* TODO XXXX: This will crash if pDCB is ever NULL */
if ((pDCB->DCBFlag & TRM_USE_TAG_QUEUING) != 0) {
pSRB = &sc->SRB[0];
pDCB->pActiveSRB = pSRB;
} else {
pSRB = pDCB->pActiveSRB;
if (pSRB == NULL || (pSRB->SRBState != TRM_DISCONNECTED)) {
/*
* abort command
*/
pSRB = &sc->SRB[0];
pSRB->SRBState = TRM_UNEXPECT_RESEL;
pDCB->pActiveSRB = pSRB;
trm_EnableMsgOut(sc, MSG_ABORT);
} else
pSRB->SRBState = TRM_DATA_XFER;
}
pSRB->ScsiPhase = PH_BUS_FREE; /* SCSI bus free Phase */
/*
* Program HA ID, target ID, period and offset
*/
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_TARGETID, target);
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_HOSTID, sc->sc_AdaptSCSIID);
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_SYNC, pDCB->SyncPeriod);
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_OFFSET, pDCB->SyncOffset);
/*
* it's important for atn stop
*/
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
DELAY(30);
/*
* SCSI command
* to rls the /ACK signal
*/
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT);
}
/*
* ------------------------------------------------------------
* Function : trm_FinishSRB
* Purpose : Complete execution of a SCSI command
* Signal completion to the generic SCSI driver
* Inputs :
* ------------------------------------------------------------
*/
void
trm_FinishSRB(struct trm_softc *sc, struct trm_scsi_req_q *pSRB)
{
struct scsi_inquiry_data *ptr;
struct scsi_sense_data *s1, *s2;
struct scsi_xfer *xs = pSRB->xs;
struct trm_dcb *pDCB = pSRB->pSRBDCB;
int target, lun;
#ifdef TRM_DEBUG0
printf("%s: trm_FinishSRB. sc = %p, pSRB = %p\n",
sc->sc_device.dv_xname, sc, pSRB);
#endif
pDCB->DCBFlag &= ~TRM_QUEUE_FULL;
if (xs == NULL) {
trm_ReleaseSRB(sc, pSRB);
return;
}
timeout_del(&xs->stimeout);
xs->status = pSRB->TargetStatus;
switch (xs->status) {
case SCSI_INTERM_COND_MET:
case SCSI_COND_MET:
case SCSI_INTERM:
case SCSI_OK:
switch (pSRB->AdaptStatus) {
case TRM_STATUS_GOOD:
if ((pSRB->SRBFlag & TRM_PARITY_ERROR) != 0) {
#ifdef TRM_DEBUG0
printf("%s: trm_FinishSRB. TRM_PARITY_ERROR\n",
sc->sc_device.dv_xname);
#endif
xs->error = XS_DRIVER_STUFFUP;
} else if ((pSRB->SRBFlag & TRM_SCSI_TIMED_OUT) != 0) {
xs->error = XS_TIMEOUT;
} else if ((pSRB->SRBFlag & TRM_AUTO_REQSENSE) != 0) {
s1 = &pSRB->scsisense;
s2 = &xs->sense;
*s2 = *s1;
xs->status = SCSI_CHECK;
xs->error = XS_SENSE;
} else
xs->error = XS_NOERROR;
break;
case TRM_OVER_UNDER_RUN:
#ifdef TRM_DEBUG0
printf("%s: trm_FinishSRB. TRM_OVER_UNDER_RUN\n",
sc->sc_device.dv_xname);
#endif
xs->error = XS_DRIVER_STUFFUP;
break;
default:
#ifdef TRM_DEBUG0
printf("%s: trm_FinishSRB. AdaptStatus Error = 0x%02x\n",
sc->sc_device.dv_xname, pSRB->AdaptStatus);
#endif
xs->error = XS_DRIVER_STUFFUP;
break;
}
break;
case SCSI_TERMINATED:
case SCSI_ACA_ACTIVE:
case SCSI_CHECK:
if ((pSRB->SRBFlag & TRM_AUTO_REQSENSE) != 0)
xs->error = XS_DRIVER_STUFFUP;
else {
trm_RequestSense(sc, pSRB);
return;
}
break;
case SCSI_QUEUE_FULL:
/* this says no more until someone completes */
pDCB->DCBFlag |= TRM_QUEUE_FULL;
trm_RewaitSRB(sc, pSRB);
return;
case SCSI_RESV_CONFLICT:
case SCSI_BUSY:
xs->error = XS_BUSY;
break;
case TRM_SCSI_UNEXP_BUS_FREE:
xs->status = SCSI_OK;
xs->error = XS_DRIVER_STUFFUP;
break;
case TRM_SCSI_BUS_RST_DETECTED:
xs->status = SCSI_OK;
xs->error = XS_RESET;
break;
case TRM_SCSI_SELECT_TIMEOUT:
xs->status = SCSI_OK;
xs->error = XS_SELTIMEOUT;
break;
default:
xs->error = XS_DRIVER_STUFFUP;
break;
}
target = xs->sc_link->target;
lun = xs->sc_link->lun;
if ((xs->flags & SCSI_POLL) != 0) {
if (xs->cmd->opcode == INQUIRY) {
ptr = (struct scsi_inquiry_data *) xs->data;
if ((xs->error != XS_NOERROR) ||
((ptr->device & SID_QUAL_BAD_LU) == SID_QUAL_BAD_LU)) {
#ifdef TRM_DEBUG0
printf("%s: trm_FinishSRB NO Device:target= %d,lun= %d\n",
sc->sc_device.dv_xname, target, lun);
#endif
free(pDCB, M_DEVBUF);
sc->pDCB[target][lun] = NULL;
pDCB = NULL;
} else
pDCB->sc_link = xs->sc_link;
}
}
trm_ReleaseSRB(sc, pSRB);
xs->flags |= ITSDONE;
/*
* Notify cmd done
*/
#ifdef TRM_DEBUG0
if ((xs->error != 0) || (xs->status != 0) || ((xs->flags & SCSI_POLL) != 0))
printf("%s: trm_FinishSRB. %d/%d xs->cmd->opcode = 0x%02x, xs->error = %d, xs->status = %d\n",
sc->sc_device.dv_xname, target, lun, xs->cmd->opcode, xs->error, xs->status);
#endif
scsi_done(xs);
}
/*
* ------------------------------------------------------------
* Function : trm_ReleaseSRB
* Purpose :
* Inputs :
* ------------------------------------------------------------
*/
void
trm_ReleaseSRB(struct trm_softc *sc, struct trm_scsi_req_q *pSRB)
{
struct scsi_xfer *xs = pSRB->xs;
int intflag;
intflag = splbio();
if (pSRB->TagNumber != TRM_NO_TAG) {
pSRB->pSRBDCB->TagMask &= ~(1 << pSRB->TagNumber);
pSRB->TagNumber = TRM_NO_TAG;
}
if (xs != NULL) {
timeout_del(&xs->stimeout);
if (xs->datalen != 0) {
bus_dmamap_sync(sc->sc_dmatag, pSRB->dmamapxfer,
0, pSRB->dmamapxfer->dm_mapsize,
(xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD :
BUS_DMASYNC_POSTWRITE);
bus_dmamap_unload(sc->sc_dmatag, pSRB->dmamapxfer);
}
}
/* SRB may have started & finished, or be waiting and timed out */
if ((pSRB->SRBFlag & TRM_ON_WAITING_SRB) != 0) {
pSRB->SRBFlag &= ~TRM_ON_WAITING_SRB;
TAILQ_REMOVE(&sc->waitingSRB, pSRB, link);
}
if ((pSRB->SRBFlag & TRM_ON_GOING_SRB) != 0) {
pSRB->SRBFlag &= ~TRM_ON_GOING_SRB;
TAILQ_REMOVE(&sc->goingSRB, pSRB, link);
}
bzero(&pSRB->SegmentX[0], sizeof(pSRB->SegmentX));
bzero(&pSRB->CmdBlock[0], sizeof(pSRB->CmdBlock));
bzero(&pSRB->scsisense, sizeof(pSRB->scsisense));
pSRB->SRBTotalXferLength = 0;
pSRB->SRBSGCount = 0;
pSRB->SRBSGIndex = 0;
pSRB->SRBFlag = 0;
pSRB->SRBState = TRM_FREE;
pSRB->AdaptStatus = TRM_STATUS_GOOD;
pSRB->TargetStatus = SCSI_OK;
pSRB->ScsiPhase = PH_BUS_FREE; /* SCSI bus free Phase */
pSRB->xs = NULL;
pSRB->pSRBDCB = NULL;
if (pSRB != &sc->SRB[0])
TAILQ_INSERT_TAIL(&sc->freeSRB, pSRB, link);
splx(intflag);
}
/*
* ------------------------------------------------------------
* Function : trm_GoingSRB_Done
* Purpose :
* Inputs :
* ------------------------------------------------------------
*/
void
trm_GoingSRB_Done(struct trm_softc *sc)
{
struct trm_scsi_req_q *pSRB;
/* ASSUME we are inside a splbio()/splx() pair */
while ((pSRB = TAILQ_FIRST(&sc->goingSRB)) != NULL) {
/* TODO XXXX: Is TIMED_OUT the best status? */
pSRB->SRBFlag |= TRM_SCSI_TIMED_OUT;
trm_FinishSRB(sc, pSRB);
}
}
/*
* ------------------------------------------------------------
* Function : trm_ResetSCSIBus
* Purpose : Reset the SCSI bus
* Inputs : struct trm_softc * -
* ------------------------------------------------------------
*/
void
trm_ResetSCSIBus(struct trm_softc *sc)
{
const bus_space_handle_t ioh = sc->sc_iohandle;
const bus_space_tag_t iot = sc->sc_iotag;
int intflag;
intflag = splbio();
sc->sc_Flag |= RESET_DEV;
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_RSTSCSI);
while ((bus_space_read_2(iot, ioh,
TRM_S1040_SCSI_INTSTATUS) & INT_SCSIRESET) == 0);
splx(intflag);
}
/*
* ------------------------------------------------------------
* Function : trm_ScsiRstDetect
* Purpose :
* Inputs :
* ------------------------------------------------------------
*/
void
trm_ScsiRstDetect(struct trm_softc *sc)
{
const bus_space_handle_t ioh = sc->sc_iohandle;
const bus_space_tag_t iot = sc->sc_iotag;
int wlval;
#ifdef TRM_DEBUG0
printf("%s: trm_ScsiRstDetect\n", sc->sc_device.dv_xname);
#endif
wlval = 1000;
/*
* delay 1 sec
*/
while (--wlval != 0)
DELAY(1000);
bus_space_write_1(iot, ioh, TRM_S1040_DMA_CONTROL, STOPDMAXFER);
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_CLRFIFO);
if ((sc->sc_Flag & RESET_DEV) != 0)
sc->sc_Flag |= RESET_DONE;
else {
sc->sc_Flag |= RESET_DETECT;
trm_ResetAllDevParam(sc);
trm_RecoverSRB(sc);
sc->pActiveDCB = NULL;
sc->sc_Flag = 0;
trm_StartWaitingSRB(sc);
}
}
/*
* ------------------------------------------------------------
* Function : trm_RequestSense
* Purpose :
* Inputs :
* ------------------------------------------------------------
*/
void
trm_RequestSense(struct trm_softc *sc, struct trm_scsi_req_q *pSRB)
{
pSRB->SRBFlag |= TRM_AUTO_REQSENSE;
/*
* Status of initiator/target
*/
pSRB->AdaptStatus = TRM_STATUS_GOOD;
pSRB->TargetStatus = SCSI_OK;
/*
* Status of initiator/target
*/
pSRB->SegmentX[0].address = pSRB->scsisensePhyAddr;
pSRB->SegmentX[0].length = sizeof(struct scsi_sense_data);
pSRB->SRBTotalXferLength = sizeof(struct scsi_sense_data);
pSRB->SRBSGCount = 1;
pSRB->SRBSGIndex = 0;
bzero(&pSRB->CmdBlock[0], sizeof(pSRB->CmdBlock));
pSRB->CmdBlock[0] = REQUEST_SENSE;
pSRB->CmdBlock[1] = (pSRB->xs->sc_link->lun) << 5;
pSRB->CmdBlock[4] = sizeof(struct scsi_sense_data);
pSRB->ScsiCmdLen = 6;
if ((pSRB->xs != NULL) && ((pSRB->xs->flags & SCSI_POLL) == 0))
timeout_add(&pSRB->xs->stimeout, (pSRB->xs->timeout/1000) * hz);
if (trm_StartSRB(sc, pSRB) != 0)
trm_RewaitSRB(sc, pSRB);
}
/*
* ------------------------------------------------------------
* Function : trm_EnableMsgOut
* Purpose : set up MsgBuf to send out a single byte message
* Inputs :
* ------------------------------------------------------------
*/
void
trm_EnableMsgOut(struct trm_softc *sc, u_int8_t msg)
{
sc->MsgBuf[0] = msg;
sc->MsgCnt = 1;
bus_space_write_2(sc->sc_iotag, sc->sc_iohandle, TRM_S1040_SCSI_CONTROL, DO_SETATN);
}
/*
* ------------------------------------------------------------
* Function : trm_linkSRB
* Purpose :
* Inputs :
* ------------------------------------------------------------
*/
void
trm_linkSRB(struct trm_softc *sc)
{
struct trm_scsi_req_q *pSRB;
int i, intflag;
intflag = splbio();
for (i = 0; i < TRM_MAX_SRB_CNT; i++) {
pSRB = &sc->SRB[i];
pSRB->PhysSRB = sc->sc_dmamap_control->dm_segs[0].ds_addr
+ i * sizeof(struct trm_scsi_req_q);
pSRB->SRBSGPhyAddr = sc->sc_dmamap_control->dm_segs[0].ds_addr
+ i * sizeof(struct trm_scsi_req_q)
+ offsetof(struct trm_scsi_req_q, SegmentX);
pSRB->scsisensePhyAddr = sc->sc_dmamap_control->dm_segs[0].ds_addr
+ i * sizeof(struct trm_scsi_req_q)
+ offsetof(struct trm_scsi_req_q, scsisense);
/*
* map all SRB space
*/
if (bus_dmamap_create(sc->sc_dmatag, TRM_MAX_PHYSG_BYTE,
TRM_MAX_SG_LISTENTRY, TRM_MAX_PHYSG_BYTE, 0,
BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
&pSRB->dmamapxfer) != 0) {
printf("%s: unable to create DMA transfer map\n",
sc->sc_device.dv_xname);
splx(intflag);
return;
}
if (i > 0)
/* We use sc->SRB[0] directly, so *don't* link it */
TAILQ_INSERT_TAIL(&sc->freeSRB, pSRB, link);
#ifdef TRM_DEBUG0
printf("pSRB = %p ", pSRB);
#endif
}
#ifdef TRM_DEBUG0
printf("\n ");
#endif
splx(intflag);
}
/*
* ------------------------------------------------------------
* Function : trm_minphys
* Purpose : limited by the number of segments in the dma segment list
* Inputs : *buf
* ------------------------------------------------------------
*/
void
trm_minphys(struct buf *bp)
{
if (bp->b_bcount > (TRM_MAX_SG_LISTENTRY-1) * (long) NBPG) {
bp->b_bcount = (TRM_MAX_SG_LISTENTRY-1) * (long) NBPG;
}
minphys(bp);
}
/*
* ------------------------------------------------------------
* Function : trm_initACB
* Purpose : initialize the internal structures for a given SCSI host
* Inputs :
* ------------------------------------------------------------
*/
void
trm_initACB(struct trm_softc *sc, int unit)
{
const bus_space_handle_t ioh = sc->sc_iohandle;
const bus_space_tag_t iot = sc->sc_iotag;
struct trm_adapter_nvram *pEEpromBuf;
struct trm_dcb *pDCB;
int target, lun;
pEEpromBuf = &trm_eepromBuf[unit];
sc->sc_config = HCC_AUTOTERM | HCC_PARITY;
if ((bus_space_read_1(iot, ioh, TRM_S1040_GEN_STATUS) & WIDESCSI) != 0)
sc->sc_config |= HCC_WIDE_CARD;
if ((pEEpromBuf->NvramChannelCfg & NAC_POWERON_SCSI_RESET) != 0)
sc->sc_config |= HCC_SCSI_RESET;
TAILQ_INIT(&sc->freeSRB);
TAILQ_INIT(&sc->waitingSRB);
TAILQ_INIT(&sc->goingSRB);
sc->pActiveDCB = NULL;
sc->sc_AdapterUnit = unit;
sc->sc_AdaptSCSIID = pEEpromBuf->NvramScsiId;
sc->sc_TagMaxNum = 2 << pEEpromBuf->NvramMaxTag;
sc->sc_Flag = 0;
/*
* put all SRB's (except [0]) onto the freeSRB list
*/
trm_linkSRB(sc);
/*
* allocate DCB array
*/
for (target = 0; target < TRM_MAX_TARGETS; target++) {
if (target == sc->sc_AdaptSCSIID)
continue;
for (lun = 0; lun < TRM_MAX_LUNS; lun++) {
pDCB = (struct trm_dcb *)malloc(sizeof(struct trm_dcb), M_DEVBUF, M_NOWAIT);
sc->pDCB[target][lun] = pDCB;
if (pDCB == NULL)
continue;
bzero(pDCB, sizeof(struct trm_dcb));
pDCB->target = target;
pDCB->lun = lun;
pDCB->pActiveSRB = NULL;
}
}
sc->sc_adapter.scsi_cmd = trm_scsi_cmd;
sc->sc_adapter.scsi_minphys = trm_minphys;
sc->sc_link.adapter_softc = sc;
sc->sc_link.adapter_target = sc->sc_AdaptSCSIID;
sc->sc_link.openings = 30; /* So TagMask (32 bit integer) always has space */
sc->sc_link.device = &trm_device;
sc->sc_link.adapter = &sc->sc_adapter;
sc->sc_link.adapter_buswidth = ((sc->sc_config & HCC_WIDE_CARD) == 0) ? 8:16;
trm_reset(sc);
}
/*
* ------------------------------------------------------------
* Function : trm_write_all
* Description : write pEEpromBuf 128 bytes to seeprom
* Input : iot, ioh - chip's base address
* Output : none
* ------------------------------------------------------------
*/
void
trm_write_all(struct trm_adapter_nvram *pEEpromBuf, bus_space_tag_t iot,
bus_space_handle_t ioh)
{
u_int8_t *bpEeprom = (u_int8_t *)pEEpromBuf;
u_int8_t bAddr;
/*
* Enable SEEPROM
*/
bus_space_write_1(iot, ioh, TRM_S1040_GEN_CONTROL,
(bus_space_read_1(iot, ioh, TRM_S1040_GEN_CONTROL) | EN_EEPROM));
/*
* Write enable
*/
trm_write_cmd(iot, ioh, 0x04, 0xFF);
bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM, 0);
trm_wait_30us(iot, ioh);
for (bAddr = 0; bAddr < 128; bAddr++, bpEeprom++)
trm_set_data(iot, ioh, bAddr, *bpEeprom);
/*
* Write disable
*/
trm_write_cmd(iot, ioh, 0x04, 0x00);
bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM, 0);
trm_wait_30us(iot, ioh);
/*
* Disable SEEPROM
*/
bus_space_write_1(iot, ioh, TRM_S1040_GEN_CONTROL,
(bus_space_read_1(iot, ioh, TRM_S1040_GEN_CONTROL) & ~EN_EEPROM));
}
/*
* ------------------------------------------------------------
* Function : trm_set_data
* Description : write one byte to seeprom
* Input : iot, ioh - chip's base address
* bAddr - address of SEEPROM
* bData - data of SEEPROM
* Output : none
* ------------------------------------------------------------
*/
void
trm_set_data(bus_space_tag_t iot, bus_space_handle_t ioh, u_int8_t bAddr,
u_int8_t bData)
{
u_int8_t bSendData;
int i;
/*
* Send write command & address
*/
trm_write_cmd(iot, ioh, 0x05, bAddr);
/*
* Write data
*/
for (i = 0; i < 8; i++, bData <<= 1) {
bSendData = NVR_SELECT;
if ((bData & 0x80) != 0) { /* Start from bit 7 */
bSendData |= NVR_BITOUT;
}
bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM, bSendData);
trm_wait_30us(iot, ioh);
bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM,
(bSendData | NVR_CLOCK));
trm_wait_30us(iot, ioh);
}
bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM, NVR_SELECT);
trm_wait_30us(iot, ioh);
/*
* Disable chip select
*/
bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM, 0);
trm_wait_30us(iot, ioh);
bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM, NVR_SELECT);
trm_wait_30us(iot, ioh);
/*
* Wait for write ready
*/
for (;;) {
bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM,
(NVR_SELECT | NVR_CLOCK));
trm_wait_30us(iot, ioh);
bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM, NVR_SELECT);
trm_wait_30us(iot, ioh);
if (bus_space_read_1(iot, ioh, TRM_S1040_GEN_NVRAM) & NVR_BITIN)
break;
}
/*
* Disable chip select
*/
bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM, 0);
}
/*
* ------------------------------------------------------------
* Function : trm_read_all
* Description : read seeprom 128 bytes to pEEpromBuf
* Input : pEEpromBuf, iot, ioh - chip's base address
* Output : none
* ------------------------------------------------------------
*/
void
trm_read_all(struct trm_adapter_nvram *pEEpromBuf, bus_space_tag_t iot,
bus_space_handle_t ioh)
{
u_int8_t *bpEeprom = (u_int8_t *)pEEpromBuf;
u_int8_t bAddr;
/*
* Enable SEEPROM
*/
bus_space_write_1(iot, ioh, TRM_S1040_GEN_CONTROL,
(bus_space_read_1(iot, ioh, TRM_S1040_GEN_CONTROL) | EN_EEPROM));
for (bAddr = 0; bAddr < 128; bAddr++, bpEeprom++)
*bpEeprom = trm_get_data(iot, ioh, bAddr);
/*
* Disable SEEPROM
*/
bus_space_write_1(iot, ioh, TRM_S1040_GEN_CONTROL,
(bus_space_read_1(iot, ioh, TRM_S1040_GEN_CONTROL) & ~EN_EEPROM));
}
/*
* ------------------------------------------------------------
* Function : trm_get_data
* Description : read one byte from seeprom
* Input : iot, ioh - chip's base address
* bAddr - address of SEEPROM
* Output : bData - data of SEEPROM
* ------------------------------------------------------------
*/
u_int8_t
trm_get_data( bus_space_tag_t iot, bus_space_handle_t ioh, u_int8_t bAddr)
{
u_int8_t bReadData, bData;
int i;
bData = 0;
/*
* Send read command & address
*/
trm_write_cmd(iot, ioh, 0x06, bAddr);
for (i = 0; i < 8; i++) {
/*
* Read data
*/
bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM,
(NVR_SELECT | NVR_CLOCK));
trm_wait_30us(iot, ioh);
bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM, NVR_SELECT);
/*
* Get data bit while falling edge
*/
bReadData = bus_space_read_1(iot, ioh, TRM_S1040_GEN_NVRAM);
bData <<= 1;
if ((bReadData & NVR_BITIN) != 0)
bData |= 1;
trm_wait_30us(iot, ioh);
}
/*
* Disable chip select
*/
bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM, 0);
return bData;
}
/*
* ------------------------------------------------------------
* Function : trm_wait_30us
* Description : wait 30 us
* Input : iot, ioh - chip's base address
* Output : none
* ------------------------------------------------------------
*/
void
trm_wait_30us(bus_space_tag_t iot, bus_space_handle_t ioh)
{
bus_space_write_1(iot, ioh, TRM_S1040_GEN_TIMER, 5);
while ((bus_space_read_1(iot, ioh, TRM_S1040_GEN_STATUS) & GTIMEOUT)
== 0);
}
/*
* ------------------------------------------------------------
* Function : trm_write_cmd
* Description : write SB and Op Code into seeprom
* Input : iot, ioh - chip's base address
* bCmd - SB + Op Code
* bAddr - address of SEEPROM
* Output : none
* ------------------------------------------------------------
*/
void
trm_write_cmd( bus_space_tag_t iot, bus_space_handle_t ioh, u_int8_t bCmd,
u_int8_t bAddr)
{
u_int8_t bSendData;
int i;
for (i = 0; i < 3; i++, bCmd <<= 1) {
/*
* Program SB + OP code
*/
bSendData = NVR_SELECT;
if (bCmd & 0x04) /* Start from bit 2 */
bSendData |= NVR_BITOUT;
bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM, bSendData);
trm_wait_30us(iot, ioh);
bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM,
(bSendData | NVR_CLOCK));
trm_wait_30us(iot, ioh);
}
for (i = 0; i < 7; i++, bAddr <<= 1) {
/*
* Program address
*/
bSendData = NVR_SELECT;
if (bAddr & 0x40) { /* Start from bit 6 */
bSendData |= NVR_BITOUT;
}
bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM, bSendData);
trm_wait_30us(iot, ioh);
bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM,
(bSendData | NVR_CLOCK));
trm_wait_30us(iot, ioh);
}
bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM, NVR_SELECT);
trm_wait_30us(iot, ioh);
}
/*
* ------------------------------------------------------------
* Function : trm_check_eeprom
* Description : read eeprom 128 bytes to pEEpromBuf and check
* checksum. If it is wrong, updated with default value.
* Input : eeprom, iot, ioh - chip's base address
* Output : none
* ------------------------------------------------------------
*/
void
trm_check_eeprom(struct trm_adapter_nvram *pEEpromBuf, bus_space_tag_t iot,
bus_space_handle_t ioh)
{
u_int32_t *dpEeprom = (u_int32_t *)pEEpromBuf->NvramTarget;
u_int32_t dAddr;
u_int16_t *wpEeprom = (u_int16_t *)pEEpromBuf;
u_int16_t wAddr, wCheckSum;
#ifdef TRM_DEBUG0
printf("\ntrm_check_eeprom\n");
#endif
trm_read_all(pEEpromBuf, iot, ioh);
wCheckSum = 0;
for (wAddr = 0; wAddr < 64; wAddr++, wpEeprom++)
wCheckSum += *wpEeprom;
if (wCheckSum != 0x1234) {
#ifdef TRM_DEBUG0
printf("TRM_S1040 EEPROM Check Sum ERROR (load default)\n");
#endif
/*
* Checksum error, load default
*/
pEEpromBuf->NvramSubVendorID[0] = (u_int8_t)PCI_VENDOR_TEKRAM2;
pEEpromBuf->NvramSubVendorID[1] = (u_int8_t)(PCI_VENDOR_TEKRAM2
>> 8);
pEEpromBuf->NvramSubSysID[0] = (u_int8_t)
PCI_PRODUCT_TEKRAM2_DC3X5U;
pEEpromBuf->NvramSubSysID[1] = (u_int8_t)
(PCI_PRODUCT_TEKRAM2_DC3X5U >> 8);
pEEpromBuf->NvramSubClass = 0;
pEEpromBuf->NvramVendorID[0] = (u_int8_t)PCI_VENDOR_TEKRAM2;
pEEpromBuf->NvramVendorID[1] = (u_int8_t)(PCI_VENDOR_TEKRAM2
>> 8);
pEEpromBuf->NvramDeviceID[0] = (u_int8_t)
PCI_PRODUCT_TEKRAM2_DC3X5U;
pEEpromBuf->NvramDeviceID[1] = (u_int8_t)
(PCI_PRODUCT_TEKRAM2_DC3X5U >> 8);
pEEpromBuf->NvramReserved = 0;
for (dAddr = 0; dAddr < 16; dAddr++, dpEeprom++)
/*
* NvmTarCfg3,NvmTarCfg2,NvmTarPeriod,NvmTarCfg0
*/
*dpEeprom = 0x00000077;
/*
* NvramMaxTag,NvramDelayTime,NvramChannelCfg,NvramScsiId
*/
*dpEeprom++ = 0x04000F07;
/*
* NvramReserved1,NvramBootLun,NvramBootTarget,NvramReserved0
*/
*dpEeprom++ = 0x00000015;
for (dAddr = 0; dAddr < 12; dAddr++, dpEeprom++)
*dpEeprom = 0;
pEEpromBuf->NvramCheckSum = 0;
for (wAddr = 0, wCheckSum =0; wAddr < 63; wAddr++, wpEeprom++)
wCheckSum += *wpEeprom;
*wpEeprom = 0x1234 - wCheckSum;
trm_write_all(pEEpromBuf, iot, ioh);
}
}
/*
* ------------------------------------------------------------
* Function : trm_initAdapter
* Purpose : initialize the SCSI chip ctrl registers
* Inputs : psh - pointer to this host adapter's structure
* ------------------------------------------------------------
*/
void
trm_initAdapter(struct trm_softc *sc)
{
const bus_space_handle_t ioh = sc->sc_iohandle;
const bus_space_tag_t iot = sc->sc_iotag;
u_int16_t wval;
u_int8_t bval;
/*
* program configuration 0
*/
if ((sc->sc_config & HCC_PARITY) != 0) {
bval = PHASELATCH | INITIATOR | BLOCKRST | PARITYCHECK;
} else {
bval = PHASELATCH | INITIATOR | BLOCKRST;
}
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_CONFIG0, bval);
/*
* program configuration 1
*/
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_CONFIG1, 0x13);
/*
* 250ms selection timeout
*/
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_TIMEOUT, TRM_SEL_TIMEOUT);
/*
* Mask all the interrupt
*/
bus_space_write_1(iot, ioh, TRM_S1040_DMA_INTEN, 0);
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_INTEN, 0);
/*
* Reset SCSI module
*/
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_RSTMODULE);
/*
* program Host ID
*/
bval = sc->sc_AdaptSCSIID;
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_HOSTID, bval);
/*
* set ansynchronous transfer
*/
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_OFFSET, 0);
/*
* Turn LED control off
*/
wval = bus_space_read_2(iot, ioh, TRM_S1040_GEN_CONTROL) & 0x7F;
bus_space_write_2(iot, ioh, TRM_S1040_GEN_CONTROL, wval);
/*
* DMA config
*/
wval = bus_space_read_2(iot, ioh, TRM_S1040_DMA_CONFIG) | DMA_ENHANCE;
bus_space_write_2(iot, ioh, TRM_S1040_DMA_CONFIG, wval);
/*
* Clear pending interrupt status
*/
bus_space_read_1(iot, ioh, TRM_S1040_SCSI_INTSTATUS);
/*
* Enable SCSI interrupts
*/
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_INTEN,
(EN_SELECT | EN_SELTIMEOUT | EN_DISCONNECT | EN_RESELECTED |
EN_SCSIRESET | EN_BUSSERVICE | EN_CMDDONE));
bus_space_write_1(iot, ioh, TRM_S1040_DMA_INTEN, EN_SCSIINTR);
}
/*
* ------------------------------------------------------------
* Function : trm_init
* Purpose : initialize the internal structures for a given SCSI host
* Inputs : host - pointer to this host adapter's structure
* Preconditions : when this function is called, the chip_type field of
* the ACB structure MUST have been set.
* ------------------------------------------------------------
*/
int
trm_init(struct trm_softc *sc, int unit)
{
const bus_space_handle_t ioh = sc->sc_iohandle;
const bus_space_tag_t iot = sc->sc_iotag;
bus_dma_segment_t seg;
int error, rseg, all_srbs_size;
/*
* EEPROM CHECKSUM
*/
trm_check_eeprom(&trm_eepromBuf[unit], iot, ioh);
/*
* MEMORY ALLOCATE FOR ADAPTER CONTROL BLOCK
*/
/*
* allocate the space for all SCSI control blocks (SRB) for DMA memory.
*/
all_srbs_size = TRM_MAX_SRB_CNT * sizeof(struct trm_scsi_req_q);
error = bus_dmamem_alloc(sc->sc_dmatag, all_srbs_size, NBPG, 0, &seg,
1, &rseg, BUS_DMA_NOWAIT);
if (error != 0) {
printf("%s: unable to allocate SCSI REQUEST BLOCKS, error = %d\n",
sc->sc_device.dv_xname, error);
/*errx(error, "%s: unable to allocate SCSI request blocks",
sc->sc_device.dv_xname);*/
return -1;
}
error = bus_dmamem_map(sc->sc_dmatag, &seg, rseg, all_srbs_size,
(caddr_t *)&sc->SRB, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
if (error != 0) {
printf("%s: unable to map SCSI REQUEST BLOCKS, error = %d\n",
sc->sc_device.dv_xname, error);
/*errx(error, "unable to map SCSI request blocks");*/
return -1;
}
error = bus_dmamap_create(sc->sc_dmatag, all_srbs_size, 1,
all_srbs_size, 0, BUS_DMA_NOWAIT,&sc->sc_dmamap_control);
if (error != 0) {
printf("%s: unable to create SRB DMA maps, error = %d\n",
sc->sc_device.dv_xname, error);
/*errx(error, "unable to create SRB DMA maps");*/
return -1;
}
error = bus_dmamap_load(sc->sc_dmatag, sc->sc_dmamap_control,
sc->SRB, all_srbs_size, NULL, BUS_DMA_NOWAIT);
if (error != 0) {
printf("%s: unable to load SRB DMA maps, error = %d\n",
sc->sc_device.dv_xname, error);
/*errx(error, "unable to load SRB DMA maps");*/
return -1;
}
#ifdef TRM_DEBUG0
printf("\n\n%s: all_srbs_size=%x\n",
sc->sc_device.dv_xname, all_srbs_size);
#endif
bzero(sc->SRB, all_srbs_size);
trm_initACB(sc, unit);
trm_initAdapter(sc);
return 0;
}
/* ------------------------------------------------------------
* Function : trm_print_info
* Purpose : Print the DCB negotiation information
* Inputs :
* ------------------------------------------------------------
*/
void
trm_print_info(struct trm_softc *sc, struct trm_dcb *pDCB)
{
int syncXfer, index;
index = pDCB->SyncPeriod & ~(WIDE_SYNC | ALT_SYNC);
printf("%s: target %d using ", sc->sc_device.dv_xname, pDCB->target);
if ((pDCB->SyncPeriod & WIDE_SYNC) != 0)
printf("16 bit ");
else
printf("8 bit ");
if (pDCB->SyncOffset == 0)
printf("Asynchronous ");
else {
syncXfer = 100000 / (trm_clock_period[index] * 4);
printf("%d.%01d MHz, Offset %d ",
syncXfer / 100, syncXfer % 100, pDCB->SyncOffset);
}
printf("data transfers ");
if ((pDCB->DCBFlag & TRM_USE_TAG_QUEUING) != 0)
printf("with Tag Queuing");
printf("\n");
}