#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>
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);
void *trm_srb_alloc(void *);
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_srb_reinit (struct trm_softc *, struct trm_scsi_req_q *);
void trm_srb_free (void *, void *);
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 *, struct trm_dcb *);
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 *);
static void *trm_SCSI_phase0[8] = {
trm_DataOutPhase0,
trm_DataInPhase0,
trm_Nop,
trm_StatusPhase0,
trm_Nop,
trm_Nop,
trm_MsgOutPhase0,
trm_MsgInPhase0,
};
static void *trm_SCSI_phase1[8] = {
trm_DataOutPhase1,
trm_DataInPhase1,
trm_CommandPhase1,
trm_StatusPhase1,
trm_Nop,
trm_Nop,
trm_MsgOutPhase1,
trm_MsgInPhase1,
};
struct trm_adapter_nvram trm_eepromBuf[TRM_MAX_ADAPTER_NUM];
u_int8_t trm_clock_period[8] = {
12,
18,
25,
31,
37,
43,
50,
62
};
void *
trm_srb_alloc(void *xsc)
{
struct trm_softc *sc = xsc;
struct trm_scsi_req_q *pSRB;
mtx_enter(&sc->sc_srb_mtx);
pSRB = TAILQ_FIRST(&sc->freeSRB);
if (pSRB != NULL)
TAILQ_REMOVE(&sc->freeSRB, pSRB, link);
mtx_leave(&sc->sc_srb_mtx);
#ifdef TRM_DEBUG0
printf("%s: trm_srb_alloc. pSRB = %p, next pSRB = %p\n",
sc->sc_device.dv_xname, pSRB, TAILQ_FIRST(&sc->freeSRB));
#endif
return pSRB;
}
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);
}
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)
goto out;
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;
}
}
out:
splx(intflag);
}
void
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, timeout, xferflags;
target = xs->sc_link->target;
lun = xs->sc_link->lun;
sc = xs->sc_link->bus->sb_adapter_softc;
ioh = sc->sc_iohandle;
iot = sc->sc_iotag;
#ifdef TRM_DEBUG0
if ((xs->flags & SCSI_POLL) != 0) {
sc_print_addr(xs->sc_link);
printf("trm_scsi_cmd. sc = %p, xs = %p, opcode = 0x%02x\n",
sc, xs, lun, xs->cmd.opcode);
}
#endif
if (target >= TRM_MAX_TARGETS) {
sc_print_addr(xs->sc_link);
printf("target >= %d\n", TRM_MAX_TARGETS);
xs->error = XS_DRIVER_STUFFUP;
scsi_done(xs);
return;
}
if (lun >= TRM_MAX_LUNS) {
sc_print_addr(xs->sc_link);
printf("lun >= %d\n", TRM_MAX_LUNS);
xs->error = XS_DRIVER_STUFFUP;
scsi_done(xs);
return;
}
pDCB = sc->pDCB[target][lun];
if (pDCB == NULL) {
xs->error = XS_DRIVER_STUFFUP;
scsi_done(xs);
return;
}
xferflags = xs->flags;
if (xferflags & SCSI_RESET) {
#ifdef TRM_DEBUG0
sc_print_addr(xs->sc_link);
printf("trm_reset via SCSI_RESET\n");
#endif
trm_reset(sc);
xs->error = XS_NOERROR;
scsi_done(xs);
return;
}
pSRB = xs->io;
trm_srb_reinit(sc, pSRB);
xs->error = XS_NOERROR;
xs->status = SCSI_OK;
xs->resid = 0;
intflag = splbio();
if (xs->datalen != 0) {
#ifdef TRM_DEBUG0
sc_print_addr(xs->sc_link);
printf("xs->datalen=%x\n", (u_int32_t)&xs->datalen);
sc_print_addr(xs->sc_link);
printf("sc->sc_dmatag=0x%x\n", (u_int32_t)sc->sc_dmatag);
sc_print_addr(xs->sc_link);
printf("pSRB->dmamapxfer=0x%x\n", (u_int32_t)pSRB->dmamapxfer);
sc_print_addr(xs->sc_link);
printf("xs->data=0x%x\n", (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) {
sc_print_addr(xs->sc_link);
printf("DMA transfer map unable to load, error = %d\n",
error);
xs->error = XS_DRIVER_STUFFUP;
splx(intflag);
scsi_done(xs);
return;
}
bus_dmamap_sync(sc->sc_dmatag, pSRB->dmamapxfer,
0, pSRB->dmamapxfer->dm_mapsize,
(xferflags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
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);
timeout_set(&xs->stimeout, trm_timeout, pSRB);
pSRB->SRBFlag |= TRM_ON_WAITING_SRB;
TAILQ_INSERT_TAIL(&sc->waitingSRB, pSRB, link);
trm_StartWaitingSRB(sc);
if ((xferflags & SCSI_POLL) == 0) {
timeout_add_msec(&xs->stimeout, xs->timeout);
splx(intflag);
return;
}
splx(intflag);
for (timeout = xs->timeout; timeout > 0; timeout--) {
intflag = splbio();
trm_Interrupt(sc);
splx(intflag);
if (ISSET(xs->flags, ITSDONE))
break;
DELAY(1000);
}
if (!ISSET(xs->flags, ITSDONE) && timeout == 0)
trm_timeout(pSRB);
scsi_done(xs);
}
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 || sc->pDCB[target][0] == NULL)
continue;
if ((sc->pDCB[target][0]->DCBFlag & TRM_QUIRKS_VALID) == 0)
quirks = SDEV_NOWIDE | SDEV_NOSYNC | SDEV_NOTAGS;
else if (sc->pDCB[target][0]->sc_link != NULL)
quirks = sc->pDCB[target][0]->sc_link->quirks;
trm_ResetDevParam(sc, sc->pDCB[target][0], quirks);
}
}
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))
pDCB->DCBFlag |= TRM_USE_TAG_QUEUING;
trm_SetXferParams(sc, pDCB, 0);
}
void
trm_RecoverSRB(struct trm_softc *sc)
{
struct trm_scsi_req_q *pSRB;
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);
}
}
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;
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);
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);
bus_space_write_1(iot, ioh, TRM_S1040_DMA_CONTROL, CLRXFIFO);
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_CLRFIFO);
trm_ResetAllDevParam(sc);
trm_GoingSRB_Done(sc, NULL);
sc->pActiveDCB = NULL;
sc->sc_Flag = 0;
trm_StartWaitingSRB(sc);
splx(intflag);
}
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->bus->sb_adapter_softc;
sc_print_addr(xs->sc_link);
printf("SCSI OpCode 0x%02x ", xs->cmd.opcode);
if (pSRB->SRBFlag & TRM_AUTO_REQSENSE)
printf("REQUEST SENSE ");
printf("timed out\n");
pSRB->SRBFlag |= TRM_SCSI_TIMED_OUT;
trm_FinishSRB(sc, pSRB);
#ifdef TRM_DEBUG0
sc_print_addr(xs->sc_link);
printf("trm_reset via trm_timeout()\n");
#endif
trm_reset(sc);
trm_StartWaitingSRB(sc);
}
}
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 ((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);
}
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;
}
}
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;
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;
}
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_DATALATCH | DO_HWRESELECT);
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_COMMAND, scsicommand);
return 0;
}
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;
if (sc == NULL)
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))
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;
phase = (u_int16_t) pSRB->ScsiPhase;
stateV = trm_SCSI_phase0[phase];
stateV(sc, pSRB, &scsi_status);
pSRB->ScsiPhase = scsi_status & PHASEMASK;
phase = (u_int16_t) scsi_status & PHASEMASK;
stateV = trm_SCSI_phase1[phase];
stateV(sc, pSRB, &scsi_status);
} else {
return 0;
}
return 1;
}
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;
break;
default:
break;
}
}
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) {
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;
}
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT);
}
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;
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT);
}
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) {
dLeftCounter = (u_int32_t)(bus_space_read_1(
iot, ioh, TRM_S1040_SCSI_FIFOCNT) & 0x1F);
if (pDCB->SyncPeriod & WIDE_SYNC) {
dLeftCounter <<= 1;
}
}
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 {
if (pSRB->SRBTotalXferLength != dLeftCounter) {
TempSRBXferredLength = pSRB->SRBTotalXferLength
- dLeftCounter;
pSRB->SRBTotalXferLength = dLeftCounter;
pseg = &pSRB->SegmentX[pSRB->SRBSGIndex];
for (SGIndexTemp = pSRB->SRBSGIndex;
SGIndexTemp < pSRB->SRBSGCount;
SGIndexTemp++) {
if (TempSRBXferredLength >= pseg->length)
TempSRBXferredLength -= pseg->length;
else {
pseg->length -=
TempSRBXferredLength;
pseg->address +=
TempSRBXferredLength;
pSRB->SRBSGIndex = SGIndexTemp;
break;
}
pseg++;
}
}
}
}
bus_space_write_1(iot, ioh, TRM_S1040_DMA_CONTROL, STOPDMAXFER);
}
void
trm_DataOutPhase1(struct trm_softc *sc, struct trm_scsi_req_q *pSRB, u_int8_t *pscsi_status)
{
trm_DataIO_transfer(sc, pSRB, XFERDATAOUT);
}
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 {
if (pSRB->SRBTotalXferLength != dLeftCounter) {
TempSRBXferredLength = pSRB->SRBTotalXferLength
- dLeftCounter;
pSRB->SRBTotalXferLength = dLeftCounter;
pseg = &pSRB->SegmentX[pSRB->SRBSGIndex];
for (SGIndexTemp = pSRB->SRBSGIndex;
SGIndexTemp < pSRB->SRBSGCount;
SGIndexTemp++) {
if (TempSRBXferredLength >=
pseg->length) {
TempSRBXferredLength -= pseg->length;
} else {
pseg->length -= TempSRBXferredLength;
pseg->address += TempSRBXferredLength;
pSRB->SRBSGIndex = SGIndexTemp;
break;
}
pseg++;
}
}
}
}
}
void
trm_DataInPhase1(struct trm_softc *sc, struct trm_scsi_req_q *pSRB, u_int8_t *pscsi_status)
{
trm_DataIO_transfer(sc, pSRB, XFERDATAIN);
}
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) {
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)));
bus_space_write_4(iot, ioh, TRM_S1040_DMA_XCNT,
((u_int32_t)(pSRB->SRBSGCount -
pSRB->SRBSGIndex) << 3));
bus_space_write_4(iot, ioh,
TRM_S1040_SCSI_COUNTER, pSRB->SRBTotalXferLength);
bus_space_write_2(iot,ioh,TRM_S1040_DMA_COMMAND, ioDir);
bval = ioDir == XFERDATAOUT ? SCMD_DMA_OUT :SCMD_DMA_IN;
} else {
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;
bval = ioDir == XFERDATAOUT ? SCMD_FIFO_OUT : SCMD_FIFO_IN;
}
bus_space_write_2(iot,ioh,TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_COMMAND, bval);
}
}
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;
*pscsi_status = PH_BUS_FREE;
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT);
}
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;
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_COMMAND, SCMD_COMP);
}
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;
bzero(&sc->MsgBuf[0], sizeof(sc->MsgBuf));
sc->MsgBuf[0] = message_in_code;
sc->MsgCnt = 1;
break;
case MSG_MESSAGE_REJECT:
if ((pDCB->DCBFlag & TRM_DOING_WIDE_NEGO) != 0) {
pDCB = pSRB->pSRBDCB;
pDCB->DCBFlag &= ~TRM_DOING_WIDE_NEGO;
pDCB->DCBFlag |= TRM_WIDE_NEGO_DONE;
if ((pDCB->DCBFlag & TRM_SYNC_NEGO_ENABLE) != 0) {
pSRB->SRBState = TRM_MSGOUT;
bus_space_write_2(iot, ioh,
TRM_S1040_SCSI_CONTROL, DO_SETATN);
} else {
bus_space_write_2(iot, ioh,
TRM_S1040_SCSI_CONTROL, DO_CLRATN);
}
} else if ((pDCB->DCBFlag & TRM_DOING_SYNC_NEGO) != 0) {
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 {
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 {
#ifdef TRM_DEBUG0
printf("%s: TRM_UNEXPECT_RESEL!\n",
sc->sc_device.dv_xname);
#endif
pSRB = &sc->SRB[0];
trm_srb_reinit(sc, pSRB);
pSRB->SRBState = TRM_UNEXPECT_RESEL;
pDCB->pActiveSRB = pSRB;
trm_EnableMsgOut(sc, MSG_ABORT_TAG);
}
}
break;
case MSG_EXTENDED:
if ((sc->MsgBuf[2] == MSG_EXT_WDTR) && (sc->MsgCnt == 4)) {
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;
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;
}
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_SETATN);
} else if ((sc->MsgBuf[2] == MSG_EXT_SDTR) && (sc->MsgCnt == 5)) {
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)) {
pDCB->SyncPeriod = 0;
pDCB->SyncOffset = 0;
} else {
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:
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;
}
}
*pscsi_status = PH_BUS_FREE;
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT);
}
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);
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_IN);
}
void
trm_Nop(struct trm_softc *sc, struct trm_scsi_req_q *pSRB, u_int8_t *pscsi_status)
{
}
void
trm_SetXferParams(struct trm_softc *sc, struct trm_dcb *pDCB, int print_info)
{
struct trm_dcb *pDCBTemp;
int lun, target;
#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);
}
void
trm_Disconnect(struct trm_softc *sc)
{
const bus_space_handle_t ioh = sc->sc_iohandle;
struct trm_scsi_req_q *pSRB;
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) {
for(j = 400; j > 0; --j)
DELAY(1);
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;
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:
trm_GoingSRB_Done(sc, pDCB);
break;
case TRM_START:
case TRM_MSGOUT:
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:
pDCB->pActiveSRB = NULL;
trm_FinishSRB(sc, pSRB);
break;
default:
break;
}
trm_StartWaitingSRB(sc);
}
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) {
pSRB = pDCB->pActiveSRB;
trm_RewaitSRB(sc, pSRB);
}
RselTarLunId = bus_space_read_2(iot, ioh, TRM_S1040_SCSI_TARGETID) & 0x1FFF;
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;
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)) {
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;
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);
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
DELAY(30);
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT);
}
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, intflag;
#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;
intflag = splbio();
if (pSRB->TagNumber != TRM_NO_TAG) {
pSRB->pSRBDCB->TagMask &= ~(1 << pSRB->TagNumber);
pSRB->TagNumber = TRM_NO_TAG;
}
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);
}
splx(intflag);
if (xs == NULL) {
return;
}
timeout_del(&xs->stimeout);
xs->status = pSRB->TargetStatus;
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);
}
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
sc_print_addr(xs->sc_link);
printf(" trm_FinishSRB. TRM_PARITY_ERROR\n");
#endif
xs->error = XS_DRIVER_STUFFUP;
} else if ((pSRB->SRBFlag & TRM_SCSI_TIMED_OUT) != 0) {
if ((pSRB->SRBFlag & TRM_AUTO_REQSENSE) == 0)
xs->error = XS_TIMEOUT;
else {
bzero(&xs->sense, sizeof(xs->sense));
xs->status = SCSI_CHECK;
xs->error = XS_SENSE;
}
} 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
sc_print_addr(xs->sc_link);
printf("trm_FinishSRB. TRM_OVER_UNDER_RUN\n");
#endif
xs->error = XS_DRIVER_STUFFUP;
break;
default:
#ifdef TRM_DEBUG0
sc_print_addr(xs->sc_link);
printf("trm_FinishSRB. AdaptStatus Error = 0x%02x\n",
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:
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 && pDCB->sc_link == NULL) {
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
sc_print_addr(xs->sc_link);
printf("trm_FinishSRB NO Device\n");
#endif
free(pDCB, M_DEVBUF, 0);
sc->pDCB[target][lun] = NULL;
pDCB = NULL;
} else
pDCB->sc_link = xs->sc_link;
}
}
#ifdef TRM_DEBUG0
if ((xs->error != 0) || (xs->status != 0) ||
((xs->flags & SCSI_POLL) != 0)) {
sc_print_addr(xs->sc_link);
printf("trm_FinishSRB. xs->cmd.opcode = 0x%02x, xs->error = %d, xs->status = %d\n",
xs->cmd.opcode, xs->error, xs->status);
}
#endif
if (ISSET(xs->flags, SCSI_POLL))
SET(xs->flags, ITSDONE);
else
scsi_done(xs);
}
void
trm_srb_reinit(struct trm_softc *sc, struct trm_scsi_req_q *pSRB)
{
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;
pSRB->xs = NULL;
pSRB->pSRBDCB = NULL;
}
void
trm_srb_free(void *xsc, void *xpSRB)
{
struct trm_softc *sc = xsc;
struct trm_scsi_req_q *pSRB = xpSRB;
trm_srb_reinit(sc, pSRB);
if (pSRB != &sc->SRB[0]) {
mtx_enter(&sc->sc_srb_mtx);
TAILQ_INSERT_TAIL(&sc->freeSRB, pSRB, link);
mtx_leave(&sc->sc_srb_mtx);
}
}
void
trm_GoingSRB_Done(struct trm_softc *sc, struct trm_dcb *pDCB)
{
struct trm_scsi_req_q *pSRB, *pNextSRB;
pSRB = TAILQ_FIRST(&sc->goingSRB);
while (pSRB != NULL) {
pNextSRB = TAILQ_NEXT(pSRB, link);
if (pDCB == NULL || pSRB->pSRBDCB == pDCB) {
pSRB->SRBFlag |= TRM_SCSI_TIMED_OUT;
trm_FinishSRB(sc, pSRB);
}
pSRB = pNextSRB;
}
}
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);
}
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;
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);
}
}
void
trm_RequestSense(struct trm_softc *sc, struct trm_scsi_req_q *pSRB)
{
pSRB->SRBFlag |= TRM_AUTO_REQSENSE;
pSRB->AdaptStatus = TRM_STATUS_GOOD;
pSRB->TargetStatus = SCSI_OK;
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_msec(&pSRB->xs->stimeout, pSRB->xs->timeout);
if (trm_StartSRB(sc, pSRB) != 0)
trm_RewaitSRB(sc, pSRB);
}
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);
}
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);
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)
TAILQ_INSERT_TAIL(&sc->freeSRB, pSRB, link);
#ifdef TRM_DEBUG0
printf("pSRB = %p ", pSRB);
#endif
}
#ifdef TRM_DEBUG0
printf("\n ");
#endif
splx(intflag);
}
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);
mtx_init(&sc->sc_srb_mtx, IPL_BIO);
scsi_iopool_init(&sc->sc_iopool, sc, trm_srb_alloc, trm_srb_free);
sc->pActiveDCB = NULL;
sc->sc_AdapterUnit = unit;
sc->sc_AdaptSCSIID = pEEpromBuf->NvramScsiId;
sc->sc_TagMaxNum = 2 << pEEpromBuf->NvramMaxTag;
sc->sc_Flag = 0;
trm_linkSRB(sc);
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 | M_ZERO);
sc->pDCB[target][lun] = pDCB;
if (pDCB == NULL)
continue;
pDCB->target = target;
pDCB->lun = lun;
pDCB->pActiveSRB = NULL;
}
}
trm_reset(sc);
}
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;
bus_space_write_1(iot, ioh, TRM_S1040_GEN_CONTROL,
(bus_space_read_1(iot, ioh, TRM_S1040_GEN_CONTROL) | EN_EEPROM));
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);
trm_write_cmd(iot, ioh, 0x04, 0x00);
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_CONTROL,
(bus_space_read_1(iot, ioh, TRM_S1040_GEN_CONTROL) & ~EN_EEPROM));
}
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;
trm_write_cmd(iot, ioh, 0x05, bAddr);
for (i = 0; i < 8; i++, bData <<= 1) {
bSendData = NVR_SELECT;
if ((bData & 0x80) != 0) {
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);
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);
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;
}
bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM, 0);
}
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;
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);
bus_space_write_1(iot, ioh, TRM_S1040_GEN_CONTROL,
(bus_space_read_1(iot, ioh, TRM_S1040_GEN_CONTROL) & ~EN_EEPROM));
}
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;
trm_write_cmd(iot, ioh, 0x06, bAddr);
for (i = 0; i < 8; i++) {
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);
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);
}
bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM, 0);
return bData;
}
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);
}
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) {
bSendData = NVR_SELECT;
if (bCmd & 0x04)
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) {
bSendData = NVR_SELECT;
if (bAddr & 0x40) {
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);
}
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
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++)
*dpEeprom = 0x00000077;
*dpEeprom++ = 0x04000F07;
*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);
}
}
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;
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);
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_CONFIG1, 0x13);
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_TIMEOUT, TRM_SEL_TIMEOUT);
bus_space_write_1(iot, ioh, TRM_S1040_DMA_INTEN, 0);
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_INTEN, 0);
bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_RSTMODULE);
bval = sc->sc_AdaptSCSIID;
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_HOSTID, bval);
bus_space_write_1(iot, ioh, TRM_S1040_SCSI_OFFSET, 0);
wval = bus_space_read_2(iot, ioh, TRM_S1040_GEN_CONTROL) & 0x7F;
bus_space_write_2(iot, ioh, TRM_S1040_GEN_CONTROL, wval);
wval = bus_space_read_2(iot, ioh, TRM_S1040_DMA_CONFIG) | DMA_ENHANCE;
bus_space_write_2(iot, ioh, TRM_S1040_DMA_CONFIG, wval);
bus_space_read_1(iot, ioh, TRM_S1040_SCSI_INTSTATUS);
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);
}
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;
trm_check_eeprom(&trm_eepromBuf[unit], iot, ioh);
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 | BUS_DMA_ZERO);
if (error != 0) {
printf("%s: unable to allocate SCSI REQUEST BLOCKS, error = %d\n",
sc->sc_device.dv_xname, error);
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);
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);
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);
return -1;
}
#ifdef TRM_DEBUG0
printf("\n\n%s: all_srbs_size=%x\n",
sc->sc_device.dv_xname, all_srbs_size);
#endif
trm_initACB(sc, unit);
trm_initAdapter(sc);
return 0;
}
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");
}