📄 sc.c
字号:
/* * Copyright (c) 1992 OMRON Corporation. * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * OMRON Corporation. * * 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. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. * * @(#)sc.c 8.2 (Berkeley) 12/6/93 *//* * sc.c -- FUJITSU MB89352 SCSI Protocole Controller (SPC) Device Driver * * remaked by A.Fujita, Mar-22-1992 * remaked again by A.Fujita, Apr-16-1992 */#define DEBUG_FUNC#include "sc.h"#if NSC > 0#include <sys/param.h>#include <sys/systm.h>#include <sys/buf.h>#include <luna68k/dev/device.h>#include <luna68k/dev/screg.h>#include <luna68k/dev/scvar.h>/* * SC Driver Options */#define QUADBYTES /* 4 bytes access to SPC DREG Reg. */#define NODISCONNECT /* not used SCSI DISCONNECT Ops. */#undef XFER_ENABLE /* using interrupt for DREG access */#define SCSI_IPL 2#define SCSI_ID 7extern char *hexstr();int scinit(), scstart(), scintr();void screset();struct driver scdriver = { scinit, "sc", scstart, (int (*)()) 0, scintr, (int (*)()) 0};struct sc_softc sc_softc[NSC];#define SC_TIMEOUT 0x01400000 /* (20971520) *//* * for DEBUG */char *scsi_status(stat) u_char stat;{ if ((stat & 0x1e) == 0) return("Good"); else if ((stat & 0x1e) == STS_CHECKCOND) return("Check Condition"); else if ((stat & 0x1e) == STS_CONDMET) return("Condition Met"); else if ((stat & 0x1e) == STS_BUSY) return("Busy"); else if ((stat & 0x1e) == STS_INTERMED) return("Intermediate status sent"); else if ((stat & 0x1e) == STS_EXT) return("Extended status valid"); else return("Unknown Status");}#ifdef DEBUG_FUNCchar *scsi_command(cmd) u_char cmd;{ if (cmd == CMD_TEST_UNIT_READY) return("TEST_UNIT_READY"); else if (cmd == CMD_REQUEST_SENSE) return("REQUEST_SENSE"); else if (cmd == CMD_INQUIRY) return("INQUIRY"); else if (cmd == CMD_READ) return("READ"); else if (cmd == CMD_WRITE) return("WRITE"); else if (cmd == CMD_READ_EXT) return("READ EXT"); else if (cmd == CMD_WRITE_EXT) return("WRITE_EXT"); else if (cmd == CMD_READ_CAPACITY) return("READ_CAPACITY"); else return(hexstr(cmd, 2));}char *scsi_mesg(mesg) u_char mesg;{ if (mesg == MSG_CMD_COMPLETE) return("Command Complete"); else if (mesg == MSG_EXT_MESSAGE) return("Extended Message"); else if (mesg == MSG_SAVE_DATA_PTR) return("Save Data Pointer"); else if (mesg == MSG_RESTORE_PTR) return("Restore Pointer"); else if (mesg == MSG_DISCONNECT) return("Disconnect"); else if (mesg == MSG_INIT_DETECT_ERROR) return("Initiator Detected Error"); else if (mesg == MSG_ABORT) return("Abort"); else if (mesg == MSG_REJECT) return("Message Reject"); else if (mesg == MSG_NOOP) return("No Operation"); else if (mesg == MSG_PARITY_ERROR) return("Message Parity Error"); else if (mesg == MSG_BUS_DEVICE_RESET) return("Bus Device Reset"); else if (mesg == MSG_IDENTIFY) return("Identify"); else if (mesg == MSG_IDENTIFY_DR) return("Identify (Disconnect)"); else return("Unknown Message");}char *phase_name(phase) u_char phase;{ if (phase == DATA_OUT_PHASE) return("Data Out"); else if (phase == DATA_IN_PHASE) return("Data In"); else if (phase == CMD_PHASE) return("Command"); else if (phase == STATUS_PHASE) return("Status"); else if (phase == BUS_FREE_PHASE) return("Bus Free"); else if (phase == ARB_SEL_PHASE) return("Arbitration/Select"); else if (phase == MESG_OUT_PHASE) return("Message Out"); else if (phase == MESG_IN_PHASE) return("Message In"); else return("Unknown");}#endif/* * Initialize SPC & Data Structure */intscinit(hc) register struct hp_ctlr *hc;{ register struct sc_softc *hs = &sc_softc[hc->hp_unit]; register int i; hc->hp_ipl = SCSI_IPL; hs->sc_hc = hc; hs->sc_sq.dq_forw = hs->sc_sq.dq_back = &hs->sc_sq; hs->sc_wq.dq_forw = hs->sc_wq.dq_back = &hs->sc_wq; hs->sc_flags = 0; hs->sc_phase = BUS_FREE_PHASE; hs->sc_stat = 0; hs->sc_msg[0] = 0; screset(hc->hp_unit); return(1);}voidscreset(unit) register int unit;{ register struct sc_softc *hs = &sc_softc[unit]; volatile register struct scsidevice *hd = (struct scsidevice *)hs->sc_hc->hp_addr; printf("sc%d: ", unit); /* * Disable interrupts then reset the FUJI chip. */ hd->scsi_sctl = SCTL_DISABLE | SCTL_CTRLRST; hd->scsi_scmd = 0; hd->scsi_pctl = 0; hd->scsi_temp = 0; hd->scsi_tch = 0; hd->scsi_tcm = 0; hd->scsi_tcl = 0; hd->scsi_ints = 0; /* We can use Asynchronous Transfer only */ printf("async"); /* * Configure MB89352 with its SCSI address, all * interrupts enabled & appropriate parity. */ hd->scsi_bdid = SCSI_ID; hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB| SCTL_PARITY_ENAB | SCTL_RESEL_ENAB | SCTL_INTR_ENAB; printf(", parity"); DELAY(400); hd->scsi_sctl &= ~SCTL_DISABLE; printf(", scsi id %d\n", SCSI_ID);}/* * SPC Arbitration/Selection routine */intissue_select(hd, target, flags) volatile register struct scsidevice *hd; u_char target; int flags;{#ifndef NODISCONNECT if (flags & DQ_DISCONNECT) { hd->scsi_scmd = SCMD_SET_ATN; }#endif hd->scsi_pctl = 0; hd->scsi_temp = (1 << SCSI_ID) | (1 << target); /* select timeout is hardcoded to 2ms */ hd->scsi_tch = 0; hd->scsi_tcm = 32; hd->scsi_tcl = 4; hd->scsi_scmd = SCMD_SELECT; return (1);}/* * SPC Manual Transfer routines *//* not yet *//* * SPC Program Transfer routines */intixfer_start(hd, len, phase) volatile register struct scsidevice *hd; register int len; register u_char phase;{ register int wait = 0; hd->scsi_sdgc = 0; hd->scsi_tch = ((len & 0xff0000) >> 16); hd->scsi_tcm = ((len & 0x00ff00) >> 8); hd->scsi_tcl = (len & 0x0000ff); hd->scsi_pctl = phase; hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR; while ((hd->scsi_ssts & SSTS_BUSY) == 0) { if (wait > SC_TIMEOUT) { panic("ixfer_start: too long wait"); } wait++; DELAY(1); }}intixfer_out(hd, len, buf) volatile register struct scsidevice *hd; register int len; register u_char *buf;{ u_char *t = buf; register int wait = 0;#ifdef QUADBYTES register int qwait = 0; register int l_len = len >> 3; register u_long * l_buf = (u_long *) buf; for(; l_len > 0; l_len--) { while ((hd->scsi_ssts & SSTS_DREG_EMPTY) == 0) { if (qwait > SC_TIMEOUT) { printf("ixfer_out: quad time out\n"); printf("ixfer_out: %d bytes sended\n", (((u_char *) l_buf) - t)); printf("ixfer_out: TC = %d\n", ( hd->scsi_tch << 16 ) | ( hd->scsi_tcm << 8 ) | ( hd->scsi_tcl )); return(-1); } qwait++; DELAY(1); } *((u_long *) &hd->scsi_dreg) = *l_buf++; *((u_long *) &hd->scsi_dreg) = *l_buf++; } len &= 0x07; buf = (u_char *) l_buf;#endif for(; len > 0; len--) { while (hd->scsi_ssts & SSTS_DREG_FULL) { if (wait > SC_TIMEOUT) { printf("ixfer_out: time out\n"); printf("ixfer_out: %d bytes sended\n", (buf - t)); return(-1); } wait++; DELAY(1); } hd->scsi_dreg = *buf++; }#ifdef QUADBYTES return(qwait);#else return(wait);#endif}intixfer_in(hd, len, buf) volatile register struct scsidevice *hd; register int len; register u_char *buf;{ u_char *t = buf; register int wait = 0;#ifdef QUADBYTES register int qwait = 0; register int l_len = len >> 3; register u_long * l_buf = (u_long *) buf; for(; l_len > 0; l_len--) { while ((hd->scsi_ssts & SSTS_DREG_FULL) == 0) { if (qwait > SC_TIMEOUT) { printf("ixfer_in: quad time out\n"); printf("ixfer_in: %d bytes recieved\n", (((u_char *) l_buf) - t)); return(-1); } qwait++; DELAY(1); } *l_buf++ = *((u_long *) &hd->scsi_dreg); *l_buf++ = *((u_long *) &hd->scsi_dreg); } len &= 0x07; buf = (u_char *) l_buf;#endif for (; len > 0; len--) { while (hd->scsi_ssts & SSTS_DREG_EMPTY) { if (wait > SC_TIMEOUT) { printf("ixfer_in: time out\n"); printf("ixfer_in: %d bytes recieved\n", (buf - t)); return(-1); } wait++; DELAY(1); } *buf++ = hd->scsi_dreg; }#ifdef QUADBYTES return(qwait);#else return(wait);#endif}#ifdef XFER_ENABLE/* * SPC Interrupt base Transfer Routines */inttxfer_start(hd, len, phase) volatile register struct scsidevice *hd; register int len; register u_char phase;{ register int wait = 0; hd->scsi_sdgc = SDGC_XFER_ENAB; /* for interrupt */ hd->scsi_tch = ((len & 0xff0000) >> 16); hd->scsi_tcm = ((len & 0x00ff00) >> 8); hd->scsi_tcl = (len & 0x0000ff); hd->scsi_pctl = phase; hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR; while ((hd->scsi_ssts & SSTS_BUSY) == 0) { if (wait > SC_TIMEOUT) { panic("ixfer_start: too long wait"); } wait++; DELAY(1); }}inttxfer_in(ctlr) register int ctlr;{ register struct sc_softc *hs = &sc_softc[ctlr]; volatile register struct scsidevice *hd = (struct scsidevice *) hs->sc_hc->hp_addr; register struct scsi_queue *dq = hs->sc_sq.dq_forw;#ifdef QUADBYTES register u_long *lp; if (hd->scsi_ssts & SSTS_DREG_FULL) { lp = (u_long *) dq->dq_xferp; *lp++ = *((u_long *) &hd->scsi_dreg); *lp++ = *((u_long *) &hd->scsi_dreg); dq->dq_xferp = (u_char *) lp; dq->dq_xfercnt -= 8; goto xfer_done; }#endif *dq->dq_xferp++ = hd->scsi_dreg; dq->dq_xfercnt--; xfer_done:#ifdef DEBUGPRINT if (dq->dq_xfercnt == 0) { dbgprintf("txfer_in: "); dbgprintf("dq->dq_bp->b_un.b_addr = 0x%s, ", hexstr(dq->dq_bp->b_un.b_addr, 8)); dbgprintf("dq->dq_xferp = 0x%s :", hexstr(dq->dq_xferp, 8)); dbgprintf("done\n"); }#endif}#endif/* * SCSI Job Handler */intscstart(ctlr) int ctlr;{ register struct sc_softc *hs = &sc_softc[ctlr]; volatile register struct scsidevice *hd = (struct scsidevice *) hs->sc_hc->hp_addr; register struct scsi_queue *dq = hs->sc_sq.dq_forw; dq->dq_imax = 0; dq->dq_imin = -1; dq->dq_omax = 0; dq->dq_omin = -1; hs->sc_flags = 0; hs->sc_phase = ARB_SEL_PHASE; hs->sc_stat = 0; hs->sc_msg[0] = 0;#ifdef DEBUGPRINT dbgprintf("\n"); dbgprintf("scstart: ID = %d\n", dq->dq_slave); dbgprintf("scstart: cdb[0] = %s\n", scsi_command(dq->dq_cdb->cdb[0])); dbgprintf("scstart: cdb[1] = 0x%s\n", hexstr(dq->dq_cdb->cdb[1], 2)); dbgprintf("scstart: cdb[2] = 0x%s\n", hexstr(dq->dq_cdb->cdb[2], 2)); dbgprintf("scstart: cdb[3] = 0x%s\n", hexstr(dq->dq_cdb->cdb[3], 2)); dbgprintf("scstart: cdb[4] = 0x%s\n", hexstr(dq->dq_cdb->cdb[4], 2)); dbgprintf("scstart: cdb[5] = 0x%s\n", hexstr(dq->dq_cdb->cdb[5], 2)); if (dq->dq_cdb->cdb[0] & 0xE0) { dbgprintf("scstart: cdb[6] = 0x%s\n", hexstr(dq->dq_cdb->cdb[6], 2)); dbgprintf("scstart: cdb[7] = 0x%s\n", hexstr(dq->dq_cdb->cdb[7], 2)); dbgprintf("scstart: cdb[8] = 0x%s\n", hexstr(dq->dq_cdb->cdb[8], 2)); dbgprintf("scstart: cdb[9] = 0x%s\n", hexstr(dq->dq_cdb->cdb[9], 2)); } dbgprintf("scstart: bp->b_bcount = %d\n", dq->dq_bp->b_bcount); dbgprintf("scstart: %s\n", phase_name(hs->sc_phase));#endif issue_select(hd, dq->dq_slave, dq->dq_flags); return(1);}int_scintr(){ register struct sc_softc *hs; volatile register struct scsidevice *hd; register int ctlr; for (ctlr = 0; ctlr < NSC; ctlr++) { hs = &sc_softc[ctlr]; hd = (struct scsidevice *) hs->sc_hc->hp_addr;#ifdef XFER_ENABLE if (((hd->scsi_psns & PHASE) == DATA_IN_PHASE) && (hd->scsi_serr & SERR_XFER_OUT)) txfer_in(ctlr);#endif if (hd->scsi_ints != 0) scintr(ctlr); } return;}intscintr(ctlr) register int ctlr;{ register struct sc_softc *hs = &sc_softc[ctlr]; volatile register struct scsidevice *hd = (struct scsidevice *) hs->sc_hc->hp_addr; register struct scsi_queue *dq = hs->sc_sq.dq_forw; register u_char ints, temp; register int i, slave; int wait, len; u_char *buf; ints = hd->scsi_ints;#ifdef DEBUGPRINT dbgprintf("scintr: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x", ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns); if (hs->sc_phase == CMD_PHASE) dbgprintf(" [%s]", scsi_command(dq->dq_cdb->cdb[0])); if (hs->sc_phase & PHASE_MSG) dbgprintf(" [%s]", scsi_mesg(hs->sc_msg[0])); dbgprintf("\n");#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -