?? sc.c
字號:
#include "sc.h"#if NSC > 0#ifndef lintstatic char sccsid[] = "@(#)sc.c 1.1 92/07/30 SMI";#endif/* * Copyright (C) 1989, Sun Microsystems, Inc. *//* * * TO DO: 1. reimplment PARITY support * 2. handle linked commands * */#include <scsi/scsi.h>#include <scsi/adapters/screg.h>#include <sys/mman.h>#include <machine/pte.h>#include <machine/cpu.h>#include <vm/seg.h>/* * Definitions *//*#define SC_PARITY /* Compile in (cough) Parity support *//*#define SC_LINKED /* Compile in linked command support *//*#define SCDEBUG /* Compile in debug code */#ifdef SC_PARITY---- BLETCH ----- PARITY NOT SUPPORTED YET#endif#ifdef SCDEBUG#define DEBUGGING (scdebug || (scsi_options & SCSI_DEBUG_HA))#define DPRINTF(str) if (DEBUGGING) sc_printf(sc, str)#define DPRINTF1(str, x) if (DEBUGGING) sc_printf(sc, str, x)#define DPRINTF2(str, x, y) if (DEBUGGING) sc_printf(sc, str, x, y)#define DPRINTF3(str, x, y, z) if (DEBUGGING) sc_printf(sc, str, x, y, z)#else#define DPRINTF#define DPRINTF1#define DPRINTF2#define DPRINTF3#endif#define TRUE 1#define FALSE 0#define UNDEFINED -1#define Tgt(sp) ((sp)->cmd_pkt.pkt_address.a_target)#define Lun(sp) ((sp)->cmd_pkt.pkt_address.a_lun)#define Nextcmd(sp) ((struct scsi_cmd *)((sp)->cmd_pkt.pkt_ha_private))#define CNAME scdriver.mdr_cname#define CNUM sc-sc_softc#define INTPENDING(reg) ((reg)->icr & (ICR_INTERRUPT_REQUEST | ICR_BUS_ERROR))/* * SCSI Architecture Interface functions */static int sc_start(), sc_abort(), sc_reset(), sc_getcap(), sc_setcap();/* * Local && h/w related functions */static void screset(), sc_watch(), sc_ustart(), sc_finish(), sc_abort_cmd();static void sc_printf(), sc_flush();/* * Local static data */static struct scsitwo sc_softc[NSC];static char *scbits = "\20\20Per\17Berr\16Odd\15IRQ\14REQ\13MSG\12CD\11IO\03Wrd\02Dma\01Ena";static long sc_kment;static int sc_mapins;#ifdef SCDEBUGstatic int scdebug;#endif SCDEBUG/* * External references */extern struct seg kseg;/* * Config dependencies */static int scprobe(), scslave(), scattach(), scpoll();int scintr();struct mb_driver scdriver = { scprobe, scslave, scattach, 0, 0, scpoll, sizeof (struct screg), "scsibus", 0, "sc", 0, MDR_BIODMA,};static intscprobe(reg, ctlr)caddr_t reg;int ctlr;{ static char scwstart = 0; register struct scsitwo *sc; register struct screg *btmp = (struct screg *) reg; /* probe for different scsi host adaptor interfaces */ if (peek((short *)&btmp->dma_count) == -1) { return (0); } /* validate ctlr by write/read/cmp with a data pattern */ btmp->dma_count = 0x6789; if (btmp->dma_count != 0x6789) { return (0); } if (ctlr >= NSC) { printf("%s%d: illegal controller number", CNAME, ctlr); return (0); } sc_kment = rmalloc(kernelmap, mmu_btopr(MMU_PAGESIZE)); if (sc_kment == 0) return (0); sc = &sc_softc[ctlr]; sc->sc_reg = btmp; sc->sc_tran.tran_start = sc_start; sc->sc_tran.tran_abort = sc_abort; sc->sc_tran.tran_reset = sc_reset; sc->sc_tran.tran_getcap = sc_getcap; sc->sc_tran.tran_setcap = sc_setcap; sc->sc_tran.tran_pktalloc = scsi_std_pktalloc; sc->sc_tran.tran_dmaget = scsi_std_dmaget; sc->sc_tran.tran_pktfree = scsi_std_pktfree; sc->sc_tran.tran_dmafree = scsi_std_dmafree; screset(sc, 0); if (!scwstart) { scwstart++; timeout (sc_watch, (caddr_t) 0, hz); } return (sizeof (struct screg));}/*ARGSUSED1*/static intscslave(md, reg)struct mb_device *md;caddr_t reg;{ struct scsitwo *sc = &sc_softc[md->md_unit]; md->md_slave = HOST_ID << 3;#ifndef SC_LINKED /* * Disable linked commands for the moment... */ if (scsi_options & SCSI_OPTIONS_LINK) { scsi_options ^= SCSI_OPTIONS_LINK; sc_printf(sc, "disabling linked command support\n"); }#endif return (1);}static intscattach(md)struct mb_device *md;{ int i; static int sc_spl = 0; struct scsitwo *sc = &sc_softc[md->md_unit]; /* * Calculate max spl value so far seen */ sc_spl = MAX(sc_spl, pritospl(md->md_intpri)); /* * Make sure that everyone, including us, is locking at * the same priority. */ for (i = 0; i <= md->md_unit; i++) { sc_softc[i].sc_tran.tran_spl = sc_spl; } /* * Initialize interrupt register */ if (md->md_mc->mc_intr) { /* set up for vectored interrupts */ sc->sc_reg->intvec = md->md_mc->mc_intr->v_vec; *(md->md_mc->mc_intr->v_vptr) = (int) sc; } else { /* use auto-vectoring */ sc->sc_reg->intvec = AUTOBASE + md->md_mc->mc_intpri; } /* * Now make ourselves known to the rest of the SCSI world */ scsi_config(&sc->sc_tran, md);}/* * * Begin of external interface routines * */static intsc_start(sp)register struct scsi_cmd *sp;{ auto int s; register struct scsitwo *sc; register struct scsi_cmd *xp; sc = (struct scsitwo *) sp->cmd_pkt.pkt_address.a_cookie; s = splr(sc->sc_tran.tran_spl); if (xp = sc->sc_que) { for (;;) { if (Tgt(xp) == Tgt(sp) && Lun(xp) == Lun(sp)) { /* Queueing error */ (void) splx(s); return (FALSE); } if (Nextcmd(xp) == 0) break; else xp = Nextcmd(xp); } Nextcmd(xp) = sp; } else { sc->sc_que = sp; } Nextcmd(sp) = 0; /* * reinitialize some fields that need it... */ sp->cmd_pkt.pkt_resid = 0; sp->cmd_pkt.pkt_reason = sp->cmd_pkt.pkt_state = sp->cmd_pkt.pkt_statistics = 0; sp->cmd_cdbp = (caddr_t) sp->cmd_pkt.pkt_cdbp; sp->cmd_scbp = sp->cmd_pkt.pkt_scbp; *sp->cmd_scbp = 0; if (sp->cmd_timeout = sp->cmd_pkt.pkt_time) sp->cmd_flags |= CFLAG_WATCH; else sp->cmd_flags &= ~CFLAG_WATCH; sp->cmd_data = sp->cmd_saved_data = sp->cmd_mapping; sp->cmd_cursubseg = &sp->cmd_subseg; sp->cmd_subseg.d_base = sp->cmd_mapping; sp->cmd_subseg.d_count = 0; sp->cmd_subseg.d_next = (struct dataseg *) 0; sp->cmd_flags &= ~(CFLAG_NEEDSEG|CFLAG_CMDDISC); /* * Okay- if this command is a polling command, * and we're not the head of the queue, we have to * wait for the commands ahead of us to finish. */ if (sp->cmd_pkt.pkt_flags & FLAG_NOINTR) { int id; while (sc->sc_que != sp) { DPRINTF ("polled command waiting\n"); sc_dopoll(sc, sc->sc_cmdid); } id = sc->sc_cmdid; DPRINTF1 ("starting polling cmd #%d\n", id); sc_ustart(sc); DPRINTF ("waiting polled cmd completion\n"); sc_dopoll(sc, id); DPRINTF1 ("polled cmd #%d complete\n", id); if (sc->sc_que) sc_ustart(sc); } else if (sc->sc_que == sp) { sc_ustart(sc); } (void) splx(s); return (TRUE);}/*ARGSUSED*/static intsc_abort(ap, pkt)struct scsi_address *ap;struct scsi_pkt *pkt;{ if (pkt != (struct scsi_pkt *) 0) return (FALSE); else return (FALSE);}static intsc_reset(ap, level)struct scsi_address *ap;int level;{ struct scsitwo *sc = (struct scsitwo *) ap->a_cookie; struct scsi_cmd *sp = sc->sc_que; screset(sc, 0); if (sp) { /* * If we're resetting everything, remove * the current wait queue from reconsideration * after we reset and blow away the current * command. */ if (level == RESET_ALL) { sp = Nextcmd(sc->sc_que); Nextcmd(sc->sc_que) = 0; } sp->cmd_pkt.pkt_reason = CMD_RESET; sc_finish(sc); /* * walk down the unrooted wait queue, 'finishing' off * all the commands therein... */ if (level == RESET_ALL) { while (sp) { struct scsi_cmd *xp; xp = Nextcmd(sp); sp->cmd_pkt.pkt_reason = CMD_RESET; (*sp->cmd_pkt.pkt_comp)(sp); sp = xp; } } return (TRUE); } else { return (FALSE); }}/*ARGSUSED*/static intsc_getcap(ap, cap)struct scsi_address *ap;char *cap;{ if (cap == (char *) 0) return (UNDEFINED); else if (strncmp("dma_max", cap, 7) == 0) return (1<<16); else if (strncmp("msg_out", cap, 7) == 0) return (0); else if (strncmp("disconnect", cap, 10) == 0) return (0); else if (strncmp("synchronous", cap, 11) == 0) return (0); else if (strncmp("parity", cap, 6) == 0) return (0); else if (strncmp("initiator-id", cap, 12) == 0) return (HOST_ID); else return (UNDEFINED);}/*ARGSUSED*/static intsc_setcap(ap, cap, value)struct scsi_address *ap;char *cap;int value;{ /* * Cannot set any values yet */ return (UNDEFINED);}/* * * Internal start routine * */static voidsc_ustart(sc)register struct scsitwo *sc;{ register i; register struct scsi_cmd *sp = sc->sc_que; char dkn; int r; if (!sp) return; else if ((dkn = sp->cmd_pkt.pkt_pmon) >= 0) { dk_busy |= (1<<dkn); dk_xfer[dkn]++; if ((sp->cmd_flags & CFLAG_DMASEND) == 0) dk_read[dkn]++; dk_wds[dkn] += sp->cmd_dmacount >> 6; } /* * sc_select will wait for the scsi bus to be free, attempt * to select the target, will set up the dma engine for any * possible dma transfer, and will set the icr bits for having * interrupts enabled if this is an interrupting command. * */ sc->sc_busy = 1; if (sc_select(sc) == FALSE) { sc_finish(sc); return; } /* * At this point, we should either ge into STATUS phase or into * COMMAND phase. */#ifdef SCDEBUG if (DEBUGGING) { sc_printf(sc, "%d.%d cmd=", Tgt(sp), Lun(sp)); for (i = 0; i < sp->cmd_cdblen; i++) { printf(" 0x%x", sp->cmd_cdbp[i]); } printf("\n"); }#endif SCDEBUG for (r = i = 0; i < sp->cmd_cdblen; i++) { if ((r = sc_putbyte(sc, ICR_COMMAND, sp->cmd_cdbp[i])) <= 0) { break; } } if (r < 0) { sc_printf(sc, "couldn't send command\n"); sc_abort_cmd(sc); } else if (i > 0) { sp->cmd_pkt.pkt_state |= STATE_SENT_CMD; sp->cmd_cdbp = (caddr_t) (((u_long)sp->cmd_cdbp) + i); } /* * We will either let interrupts drive us the rest of the * way, or call a polling routine to do that for us */}static int
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -