154004Sfujita /*
254004Sfujita * Copyright (c) 1992 OMRON Corporation.
363192Sbostic * Copyright (c) 1992, 1993
463192Sbostic * The Regents of the University of California. All rights reserved.
554004Sfujita *
654004Sfujita * This code is derived from software contributed to Berkeley by
754004Sfujita * OMRON Corporation.
854004Sfujita *
954004Sfujita * %sccs.include.redist.c%
1054004Sfujita *
11*65034Sakito * @(#)sc.c 8.2 (Berkeley) 12/06/93
1254004Sfujita */
1354004Sfujita
1454004Sfujita /*
1554004Sfujita * sc.c -- FUJITSU MB89352 SCSI Protocole Controller (SPC) Device Driver
1654004Sfujita *
1754004Sfujita * remaked by A.Fujita, Mar-22-1992
1854004Sfujita * remaked again by A.Fujita, Apr-16-1992
1954004Sfujita */
2054004Sfujita
2154004Sfujita #define DEBUG_FUNC
2254004Sfujita
2354004Sfujita #include "sc.h"
2454004Sfujita #if NSC > 0
2554004Sfujita
2656519Sbostic #include <sys/param.h>
2756519Sbostic #include <sys/systm.h>
2856519Sbostic #include <sys/buf.h>
2954004Sfujita
3056519Sbostic #include <luna68k/dev/device.h>
31*65034Sakito #include <luna68k/dev/screg.h>
32*65034Sakito #include <luna68k/dev/scvar.h>
3354004Sfujita
3454004Sfujita /*
3554004Sfujita * SC Driver Options
3654004Sfujita */
3754004Sfujita
3854004Sfujita #define QUADBYTES /* 4 bytes access to SPC DREG Reg. */
3954004Sfujita #define NODISCONNECT /* not used SCSI DISCONNECT Ops. */
4054004Sfujita #undef XFER_ENABLE /* using interrupt for DREG access */
4154004Sfujita
4254004Sfujita
4354004Sfujita #define SCSI_IPL 2
4454004Sfujita #define SCSI_ID 7
4554004Sfujita
4654004Sfujita extern char *hexstr();
4754004Sfujita
4854004Sfujita int scinit(), scstart(), scintr();
4954004Sfujita void screset();
5054004Sfujita struct driver scdriver = {
5154004Sfujita scinit, "sc", scstart, (int (*)()) 0, scintr, (int (*)()) 0
5254004Sfujita };
5354004Sfujita
54*65034Sakito struct sc_softc sc_softc[NSC];
5554004Sfujita
5654004Sfujita
5754004Sfujita #define SC_TIMEOUT 0x01400000 /* (20971520) */
5854004Sfujita
5954004Sfujita
6054004Sfujita /*
6154004Sfujita * for DEBUG
6254004Sfujita */
6354004Sfujita
6454004Sfujita char *
scsi_status(stat)6554004Sfujita scsi_status(stat)
6654004Sfujita u_char stat;
6754004Sfujita {
6854004Sfujita if ((stat & 0x1e) == 0)
6954004Sfujita return("Good");
7054004Sfujita else if ((stat & 0x1e) == STS_CHECKCOND)
7154004Sfujita return("Check Condition");
7254004Sfujita else if ((stat & 0x1e) == STS_CONDMET)
7354004Sfujita return("Condition Met");
7454004Sfujita else if ((stat & 0x1e) == STS_BUSY)
7554004Sfujita return("Busy");
7654004Sfujita else if ((stat & 0x1e) == STS_INTERMED)
7754004Sfujita return("Intermediate status sent");
7854004Sfujita else if ((stat & 0x1e) == STS_EXT)
7954004Sfujita return("Extended status valid");
8054004Sfujita else
8154004Sfujita return("Unknown Status");
8254004Sfujita }
8354004Sfujita
8454004Sfujita #ifdef DEBUG_FUNC
8554004Sfujita
8654004Sfujita char *
scsi_command(cmd)8754004Sfujita scsi_command(cmd)
8854004Sfujita u_char cmd;
8954004Sfujita {
9054004Sfujita if (cmd == CMD_TEST_UNIT_READY)
9154004Sfujita return("TEST_UNIT_READY");
9254004Sfujita else if (cmd == CMD_REQUEST_SENSE)
9354004Sfujita return("REQUEST_SENSE");
9454004Sfujita else if (cmd == CMD_INQUIRY)
9554004Sfujita return("INQUIRY");
9654004Sfujita else if (cmd == CMD_READ)
9754004Sfujita return("READ");
9854004Sfujita else if (cmd == CMD_WRITE)
9954004Sfujita return("WRITE");
10054004Sfujita else if (cmd == CMD_READ_EXT)
10154004Sfujita return("READ EXT");
10254004Sfujita else if (cmd == CMD_WRITE_EXT)
10354004Sfujita return("WRITE_EXT");
10454004Sfujita else if (cmd == CMD_READ_CAPACITY)
10554004Sfujita return("READ_CAPACITY");
10654004Sfujita else
10754004Sfujita return(hexstr(cmd, 2));
10854004Sfujita }
10954004Sfujita
11054004Sfujita char *
scsi_mesg(mesg)11154004Sfujita scsi_mesg(mesg)
11254004Sfujita u_char mesg;
11354004Sfujita {
11454004Sfujita if (mesg == MSG_CMD_COMPLETE)
11554004Sfujita return("Command Complete");
11654004Sfujita else if (mesg == MSG_EXT_MESSAGE)
11754004Sfujita return("Extended Message");
11854004Sfujita else if (mesg == MSG_SAVE_DATA_PTR)
11954004Sfujita return("Save Data Pointer");
12054004Sfujita else if (mesg == MSG_RESTORE_PTR)
12154004Sfujita return("Restore Pointer");
12254004Sfujita else if (mesg == MSG_DISCONNECT)
12354004Sfujita return("Disconnect");
12454004Sfujita else if (mesg == MSG_INIT_DETECT_ERROR)
12554004Sfujita return("Initiator Detected Error");
12654004Sfujita else if (mesg == MSG_ABORT)
12754004Sfujita return("Abort");
12854004Sfujita else if (mesg == MSG_REJECT)
12954004Sfujita return("Message Reject");
13054004Sfujita else if (mesg == MSG_NOOP)
13154004Sfujita return("No Operation");
13254004Sfujita else if (mesg == MSG_PARITY_ERROR)
13354004Sfujita return("Message Parity Error");
13454004Sfujita else if (mesg == MSG_BUS_DEVICE_RESET)
13554004Sfujita return("Bus Device Reset");
13654004Sfujita else if (mesg == MSG_IDENTIFY)
13754004Sfujita return("Identify");
13854004Sfujita else if (mesg == MSG_IDENTIFY_DR)
13954004Sfujita return("Identify (Disconnect)");
14054004Sfujita else
14154004Sfujita return("Unknown Message");
14254004Sfujita }
14354004Sfujita
14454004Sfujita char *
phase_name(phase)14554004Sfujita phase_name(phase)
14654004Sfujita u_char phase;
14754004Sfujita {
14854004Sfujita if (phase == DATA_OUT_PHASE)
14954004Sfujita return("Data Out");
15054004Sfujita else if (phase == DATA_IN_PHASE)
15154004Sfujita return("Data In");
15254004Sfujita else if (phase == CMD_PHASE)
15354004Sfujita return("Command");
15454004Sfujita else if (phase == STATUS_PHASE)
15554004Sfujita return("Status");
15654004Sfujita else if (phase == BUS_FREE_PHASE)
15754004Sfujita return("Bus Free");
15854004Sfujita else if (phase == ARB_SEL_PHASE)
15954004Sfujita return("Arbitration/Select");
16054004Sfujita else if (phase == MESG_OUT_PHASE)
16154004Sfujita return("Message Out");
16254004Sfujita else if (phase == MESG_IN_PHASE)
16354004Sfujita return("Message In");
16454004Sfujita else
16554004Sfujita return("Unknown");
16654004Sfujita }
16754004Sfujita #endif
16854004Sfujita
16954004Sfujita /*
17054004Sfujita * Initialize SPC & Data Structure
17154004Sfujita */
17254004Sfujita
17354004Sfujita int
scinit(hc)17454004Sfujita scinit(hc)
17554004Sfujita register struct hp_ctlr *hc;
17654004Sfujita {
177*65034Sakito register struct sc_softc *hs = &sc_softc[hc->hp_unit];
17854004Sfujita register int i;
17954004Sfujita
18054004Sfujita hc->hp_ipl = SCSI_IPL;
18154004Sfujita hs->sc_hc = hc;
18254004Sfujita hs->sc_sq.dq_forw = hs->sc_sq.dq_back = &hs->sc_sq;
18354004Sfujita hs->sc_wq.dq_forw = hs->sc_wq.dq_back = &hs->sc_wq;
18454004Sfujita
18554004Sfujita hs->sc_flags = 0;
18654004Sfujita hs->sc_phase = BUS_FREE_PHASE;
18754004Sfujita
18854004Sfujita hs->sc_stat = 0;
18954004Sfujita hs->sc_msg[0] = 0;
19054004Sfujita
19154004Sfujita screset(hc->hp_unit);
19254004Sfujita
19354004Sfujita return(1);
19454004Sfujita }
19554004Sfujita
19654004Sfujita void
screset(unit)19754004Sfujita screset(unit)
19854004Sfujita register int unit;
19954004Sfujita {
200*65034Sakito register struct sc_softc *hs = &sc_softc[unit];
20154004Sfujita volatile register struct scsidevice *hd =
20254004Sfujita (struct scsidevice *)hs->sc_hc->hp_addr;
20354004Sfujita
20454004Sfujita printf("sc%d: ", unit);
20554004Sfujita
20654004Sfujita /*
20754004Sfujita * Disable interrupts then reset the FUJI chip.
20854004Sfujita */
20954004Sfujita
21054004Sfujita hd->scsi_sctl = SCTL_DISABLE | SCTL_CTRLRST;
21154004Sfujita hd->scsi_scmd = 0;
21254004Sfujita hd->scsi_pctl = 0;
21354004Sfujita hd->scsi_temp = 0;
21454004Sfujita hd->scsi_tch = 0;
21554004Sfujita hd->scsi_tcm = 0;
21654004Sfujita hd->scsi_tcl = 0;
21754004Sfujita hd->scsi_ints = 0;
21854004Sfujita
21954004Sfujita /* We can use Asynchronous Transfer only */
22054004Sfujita printf("async");
22154004Sfujita
22254004Sfujita /*
22354004Sfujita * Configure MB89352 with its SCSI address, all
22454004Sfujita * interrupts enabled & appropriate parity.
22554004Sfujita */
22654004Sfujita hd->scsi_bdid = SCSI_ID;
22754004Sfujita hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB|
22854004Sfujita SCTL_PARITY_ENAB | SCTL_RESEL_ENAB |
22954004Sfujita SCTL_INTR_ENAB;
23054004Sfujita printf(", parity");
23154004Sfujita
23254004Sfujita DELAY(400);
23354004Sfujita hd->scsi_sctl &= ~SCTL_DISABLE;
23454004Sfujita
23554004Sfujita printf(", scsi id %d\n", SCSI_ID);
23654004Sfujita }
23754004Sfujita
23854004Sfujita
23954004Sfujita /*
24054004Sfujita * SPC Arbitration/Selection routine
24154004Sfujita */
24254004Sfujita
24354004Sfujita int
issue_select(hd,target,flags)24454004Sfujita issue_select(hd, target, flags)
24554004Sfujita volatile register struct scsidevice *hd;
24654004Sfujita u_char target;
24754004Sfujita int flags;
24854004Sfujita {
24954004Sfujita #ifndef NODISCONNECT
25054004Sfujita if (flags & DQ_DISCONNECT) {
25154004Sfujita hd->scsi_scmd = SCMD_SET_ATN;
25254004Sfujita }
25354004Sfujita #endif
25454004Sfujita
25554004Sfujita hd->scsi_pctl = 0;
25654004Sfujita hd->scsi_temp = (1 << SCSI_ID) | (1 << target);
25754004Sfujita
25854004Sfujita /* select timeout is hardcoded to 2ms */
25954004Sfujita hd->scsi_tch = 0;
26054004Sfujita hd->scsi_tcm = 32;
26154004Sfujita hd->scsi_tcl = 4;
26254004Sfujita
26354004Sfujita hd->scsi_scmd = SCMD_SELECT;
26454004Sfujita
26554004Sfujita return (1);
26654004Sfujita }
26754004Sfujita
26854004Sfujita
26954004Sfujita /*
27054004Sfujita * SPC Manual Transfer routines
27154004Sfujita */
27254004Sfujita
27354004Sfujita /* not yet */
27454004Sfujita
27554004Sfujita
27654004Sfujita /*
27754004Sfujita * SPC Program Transfer routines
27854004Sfujita */
27954004Sfujita
28054004Sfujita int
ixfer_start(hd,len,phase)28154004Sfujita ixfer_start(hd, len, phase)
28254004Sfujita volatile register struct scsidevice *hd;
28354004Sfujita register int len;
28454004Sfujita register u_char phase;
28554004Sfujita {
28654004Sfujita register int wait = 0;
28754004Sfujita
28854004Sfujita hd->scsi_sdgc = 0;
28954004Sfujita
29054004Sfujita hd->scsi_tch = ((len & 0xff0000) >> 16);
29154004Sfujita hd->scsi_tcm = ((len & 0x00ff00) >> 8);
29254004Sfujita hd->scsi_tcl = (len & 0x0000ff);
29354004Sfujita hd->scsi_pctl = phase;
29454004Sfujita hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR;
29554004Sfujita
29654004Sfujita while ((hd->scsi_ssts & SSTS_BUSY) == 0) {
29754004Sfujita if (wait > SC_TIMEOUT) {
29854004Sfujita panic("ixfer_start: too long wait");
29954004Sfujita }
30054004Sfujita wait++;
30154004Sfujita DELAY(1);
30254004Sfujita }
30354004Sfujita }
30454004Sfujita
30554004Sfujita int
ixfer_out(hd,len,buf)30654004Sfujita ixfer_out(hd, len, buf)
30754004Sfujita volatile register struct scsidevice *hd;
30854004Sfujita register int len;
30954004Sfujita register u_char *buf;
31054004Sfujita {
31154004Sfujita u_char *t = buf;
31254004Sfujita register int wait = 0;
31354004Sfujita #ifdef QUADBYTES
31454004Sfujita register int qwait = 0;
31554004Sfujita register int l_len = len >> 3;
31654004Sfujita register u_long * l_buf = (u_long *) buf;
31754004Sfujita
31854004Sfujita for(; l_len > 0; l_len--) {
31954004Sfujita while ((hd->scsi_ssts & SSTS_DREG_EMPTY) == 0) {
32054004Sfujita if (qwait > SC_TIMEOUT) {
32154004Sfujita printf("ixfer_out: quad time out\n");
32254004Sfujita printf("ixfer_out: %d bytes sended\n",
32354004Sfujita (((u_char *) l_buf) - t));
32454004Sfujita printf("ixfer_out: TC = %d\n",
32554004Sfujita ( hd->scsi_tch << 16 ) |
32654004Sfujita ( hd->scsi_tcm << 8 ) |
32754004Sfujita ( hd->scsi_tcl ));
32854004Sfujita return(-1);
32954004Sfujita }
33054004Sfujita qwait++;
33154004Sfujita DELAY(1);
33254004Sfujita }
33354004Sfujita *((u_long *) &hd->scsi_dreg) = *l_buf++;
33454004Sfujita *((u_long *) &hd->scsi_dreg) = *l_buf++;
33554004Sfujita }
33654004Sfujita
33754004Sfujita len &= 0x07;
33854004Sfujita buf = (u_char *) l_buf;
33954004Sfujita #endif
34054004Sfujita for(; len > 0; len--) {
34154004Sfujita while (hd->scsi_ssts & SSTS_DREG_FULL) {
34254004Sfujita if (wait > SC_TIMEOUT) {
34354004Sfujita printf("ixfer_out: time out\n");
34454004Sfujita printf("ixfer_out: %d bytes sended\n",
34554004Sfujita (buf - t));
34654004Sfujita return(-1);
34754004Sfujita }
34854004Sfujita wait++;
34954004Sfujita DELAY(1);
35054004Sfujita }
35154004Sfujita hd->scsi_dreg = *buf++;
35254004Sfujita }
35354004Sfujita
35454004Sfujita #ifdef QUADBYTES
35554004Sfujita return(qwait);
35654004Sfujita #else
35754004Sfujita return(wait);
35854004Sfujita #endif
35954004Sfujita }
36054004Sfujita
36154004Sfujita int
ixfer_in(hd,len,buf)36254004Sfujita ixfer_in(hd, len, buf)
36354004Sfujita volatile register struct scsidevice *hd;
36454004Sfujita register int len;
36554004Sfujita register u_char *buf;
36654004Sfujita {
36754004Sfujita u_char *t = buf;
36854004Sfujita register int wait = 0;
36954004Sfujita #ifdef QUADBYTES
37054004Sfujita register int qwait = 0;
37154004Sfujita register int l_len = len >> 3;
37254004Sfujita register u_long * l_buf = (u_long *) buf;
37354004Sfujita
37454004Sfujita for(; l_len > 0; l_len--) {
37554004Sfujita while ((hd->scsi_ssts & SSTS_DREG_FULL) == 0) {
37654004Sfujita if (qwait > SC_TIMEOUT) {
37754004Sfujita printf("ixfer_in: quad time out\n");
37854004Sfujita printf("ixfer_in: %d bytes recieved\n",
37954004Sfujita (((u_char *) l_buf) - t));
38054004Sfujita return(-1);
38154004Sfujita }
38254004Sfujita qwait++;
38354004Sfujita DELAY(1);
38454004Sfujita }
38554004Sfujita *l_buf++ = *((u_long *) &hd->scsi_dreg);
38654004Sfujita *l_buf++ = *((u_long *) &hd->scsi_dreg);
38754004Sfujita }
38854004Sfujita
38954004Sfujita len &= 0x07;
39054004Sfujita buf = (u_char *) l_buf;
39154004Sfujita #endif
39254004Sfujita for (; len > 0; len--) {
39354004Sfujita while (hd->scsi_ssts & SSTS_DREG_EMPTY) {
39454004Sfujita if (wait > SC_TIMEOUT) {
39554004Sfujita printf("ixfer_in: time out\n");
39654004Sfujita printf("ixfer_in: %d bytes recieved\n",
39754004Sfujita (buf - t));
39854004Sfujita return(-1);
39954004Sfujita }
40054004Sfujita wait++;
40154004Sfujita DELAY(1);
40254004Sfujita }
40354004Sfujita *buf++ = hd->scsi_dreg;
40454004Sfujita }
40554004Sfujita
40654004Sfujita
40754004Sfujita #ifdef QUADBYTES
40854004Sfujita return(qwait);
40954004Sfujita #else
41054004Sfujita return(wait);
41154004Sfujita #endif
41254004Sfujita }
41354004Sfujita
41454004Sfujita
41554004Sfujita #ifdef XFER_ENABLE
41654004Sfujita /*
41754004Sfujita * SPC Interrupt base Transfer Routines
41854004Sfujita */
41954004Sfujita
42054004Sfujita int
txfer_start(hd,len,phase)42154004Sfujita txfer_start(hd, len, phase)
42254004Sfujita volatile register struct scsidevice *hd;
42354004Sfujita register int len;
42454004Sfujita register u_char phase;
42554004Sfujita {
42654004Sfujita register int wait = 0;
42754004Sfujita
42854004Sfujita hd->scsi_sdgc = SDGC_XFER_ENAB; /* for interrupt */
42954004Sfujita
43054004Sfujita hd->scsi_tch = ((len & 0xff0000) >> 16);
43154004Sfujita hd->scsi_tcm = ((len & 0x00ff00) >> 8);
43254004Sfujita hd->scsi_tcl = (len & 0x0000ff);
43354004Sfujita hd->scsi_pctl = phase;
43454004Sfujita hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR;
43554004Sfujita
43654004Sfujita while ((hd->scsi_ssts & SSTS_BUSY) == 0) {
43754004Sfujita if (wait > SC_TIMEOUT) {
43854004Sfujita panic("ixfer_start: too long wait");
43954004Sfujita }
44054004Sfujita wait++;
44154004Sfujita DELAY(1);
44254004Sfujita }
44354004Sfujita }
44454004Sfujita
44554004Sfujita int
txfer_in(ctlr)44654004Sfujita txfer_in(ctlr)
44754004Sfujita register int ctlr;
44854004Sfujita {
449*65034Sakito register struct sc_softc *hs = &sc_softc[ctlr];
45054004Sfujita volatile register struct scsidevice *hd = (struct scsidevice *) hs->sc_hc->hp_addr;
45154004Sfujita register struct scsi_queue *dq = hs->sc_sq.dq_forw;
45254004Sfujita #ifdef QUADBYTES
45354004Sfujita register u_long *lp;
45454004Sfujita
45554004Sfujita if (hd->scsi_ssts & SSTS_DREG_FULL) {
45654004Sfujita lp = (u_long *) dq->dq_xferp;
45754004Sfujita
45854004Sfujita *lp++ = *((u_long *) &hd->scsi_dreg);
45954004Sfujita *lp++ = *((u_long *) &hd->scsi_dreg);
46054004Sfujita
46154004Sfujita dq->dq_xferp = (u_char *) lp;
46254004Sfujita dq->dq_xfercnt -= 8;
46354004Sfujita
46454004Sfujita goto xfer_done;
46554004Sfujita }
46654004Sfujita #endif
46754004Sfujita
46854004Sfujita *dq->dq_xferp++ = hd->scsi_dreg;
46954004Sfujita dq->dq_xfercnt--;
47054004Sfujita
47154004Sfujita xfer_done:
47254004Sfujita #ifdef DEBUGPRINT
47354004Sfujita if (dq->dq_xfercnt == 0) {
47454004Sfujita dbgprintf("txfer_in: ");
47554004Sfujita dbgprintf("dq->dq_bp->b_un.b_addr = 0x%s, ", hexstr(dq->dq_bp->b_un.b_addr, 8));
47654004Sfujita dbgprintf("dq->dq_xferp = 0x%s :", hexstr(dq->dq_xferp, 8));
47754004Sfujita dbgprintf("done\n");
47854004Sfujita }
47954004Sfujita #endif
48054004Sfujita }
48154004Sfujita #endif
48254004Sfujita
48354004Sfujita /*
48454004Sfujita * SCSI Job Handler
48554004Sfujita */
48654004Sfujita
48754004Sfujita int
scstart(ctlr)48854004Sfujita scstart(ctlr)
48954004Sfujita int ctlr;
49054004Sfujita {
491*65034Sakito register struct sc_softc *hs = &sc_softc[ctlr];
49254004Sfujita volatile register struct scsidevice *hd =
49354004Sfujita (struct scsidevice *) hs->sc_hc->hp_addr;
49454004Sfujita register struct scsi_queue *dq = hs->sc_sq.dq_forw;
49554004Sfujita
49654004Sfujita dq->dq_imax = 0;
49754004Sfujita dq->dq_imin = -1;
49854004Sfujita dq->dq_omax = 0;
49954004Sfujita dq->dq_omin = -1;
50054004Sfujita
50154004Sfujita hs->sc_flags = 0;
50254004Sfujita hs->sc_phase = ARB_SEL_PHASE;
50354004Sfujita
50454004Sfujita hs->sc_stat = 0;
50554004Sfujita hs->sc_msg[0] = 0;
50654004Sfujita
50754004Sfujita #ifdef DEBUGPRINT
50854004Sfujita dbgprintf("\n");
50954004Sfujita dbgprintf("scstart: ID = %d\n", dq->dq_slave);
51054004Sfujita dbgprintf("scstart: cdb[0] = %s\n", scsi_command(dq->dq_cdb->cdb[0]));
51154004Sfujita dbgprintf("scstart: cdb[1] = 0x%s\n", hexstr(dq->dq_cdb->cdb[1], 2));
51254004Sfujita dbgprintf("scstart: cdb[2] = 0x%s\n", hexstr(dq->dq_cdb->cdb[2], 2));
51354004Sfujita dbgprintf("scstart: cdb[3] = 0x%s\n", hexstr(dq->dq_cdb->cdb[3], 2));
51454004Sfujita dbgprintf("scstart: cdb[4] = 0x%s\n", hexstr(dq->dq_cdb->cdb[4], 2));
51554004Sfujita dbgprintf("scstart: cdb[5] = 0x%s\n", hexstr(dq->dq_cdb->cdb[5], 2));
51654004Sfujita if (dq->dq_cdb->cdb[0] & 0xE0) {
51754004Sfujita dbgprintf("scstart: cdb[6] = 0x%s\n", hexstr(dq->dq_cdb->cdb[6], 2));
51854004Sfujita dbgprintf("scstart: cdb[7] = 0x%s\n", hexstr(dq->dq_cdb->cdb[7], 2));
51954004Sfujita dbgprintf("scstart: cdb[8] = 0x%s\n", hexstr(dq->dq_cdb->cdb[8], 2));
52054004Sfujita dbgprintf("scstart: cdb[9] = 0x%s\n", hexstr(dq->dq_cdb->cdb[9], 2));
52154004Sfujita }
52254004Sfujita dbgprintf("scstart: bp->b_bcount = %d\n", dq->dq_bp->b_bcount);
52354004Sfujita dbgprintf("scstart: %s\n", phase_name(hs->sc_phase));
52454004Sfujita #endif
52554004Sfujita
52654004Sfujita issue_select(hd, dq->dq_slave, dq->dq_flags);
52754004Sfujita
52854004Sfujita return(1);
52954004Sfujita }
53054004Sfujita
53154004Sfujita int
_scintr()53254004Sfujita _scintr()
53354004Sfujita {
534*65034Sakito register struct sc_softc *hs;
53554004Sfujita volatile register struct scsidevice *hd;
53654004Sfujita register int ctlr;
53754004Sfujita
53854004Sfujita for (ctlr = 0; ctlr < NSC; ctlr++) {
539*65034Sakito hs = &sc_softc[ctlr];
54054004Sfujita hd = (struct scsidevice *) hs->sc_hc->hp_addr;
54154004Sfujita
54254004Sfujita #ifdef XFER_ENABLE
54354004Sfujita if (((hd->scsi_psns & PHASE) == DATA_IN_PHASE) &&
54454004Sfujita (hd->scsi_serr & SERR_XFER_OUT))
54554004Sfujita txfer_in(ctlr);
54654004Sfujita #endif
54754004Sfujita
54854004Sfujita if (hd->scsi_ints != 0)
54954004Sfujita scintr(ctlr);
55054004Sfujita }
55154004Sfujita
55254004Sfujita return;
55354004Sfujita }
55454004Sfujita
55554004Sfujita int
scintr(ctlr)55654004Sfujita scintr(ctlr)
55754004Sfujita register int ctlr;
55854004Sfujita {
559*65034Sakito register struct sc_softc *hs = &sc_softc[ctlr];
56054004Sfujita volatile register struct scsidevice *hd = (struct scsidevice *) hs->sc_hc->hp_addr;
56154004Sfujita register struct scsi_queue *dq = hs->sc_sq.dq_forw;
56254004Sfujita register u_char ints, temp;
56354004Sfujita register int i, slave;
56454004Sfujita int wait, len;
56554004Sfujita u_char *buf;
56654004Sfujita
56754004Sfujita ints = hd->scsi_ints;
56854004Sfujita
56954004Sfujita #ifdef DEBUGPRINT
57054004Sfujita dbgprintf("scintr: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x",
57154004Sfujita ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns);
57254004Sfujita if (hs->sc_phase == CMD_PHASE)
57354004Sfujita dbgprintf(" [%s]", scsi_command(dq->dq_cdb->cdb[0]));
57454004Sfujita if (hs->sc_phase & PHASE_MSG)
57554004Sfujita dbgprintf(" [%s]", scsi_mesg(hs->sc_msg[0]));
57654004Sfujita dbgprintf("\n");
57754004Sfujita #endif
57854004Sfujita
57954004Sfujita if (ints & INTS_DISCON) {
58054004Sfujita if (hs->sc_msg[0] == MSG_CMD_COMPLETE) {
58154004Sfujita hd->scsi_ints = ints;
58254004Sfujita
58354004Sfujita if (hs->sc_lock != NULL) {
58454004Sfujita *(hs->sc_lock) = SC_IO_COMPLETE;
58554004Sfujita } else {
58654004Sfujita (dq->dq_driver->d_intr)(dq->dq_unit, hs->sc_stat);
58754004Sfujita }
58854004Sfujita
58954004Sfujita return;
59054004Sfujita #ifndef NODISCONNECT
59154004Sfujita } else if (hs->sc_msg[0] == MSG_DISCONNECT) {
59254004Sfujita #ifdef DEBUGPRINT
59354004Sfujita dbgprintf("scintr: DISCONNECT : ctlr = %d, slave = %d, cdb = %s\n",
59454004Sfujita dq->dq_ctlr, dq->dq_slave, scsi_command(dq->dq_cdb->cdb[0]));
59554004Sfujita #endif
59654004Sfujita
59754004Sfujita hd->scsi_ints = ints;
59854004Sfujita
59954004Sfujita scpend(dq);
60054004Sfujita
60154004Sfujita dq = hs->sc_sq.dq_forw;
60254004Sfujita
60354004Sfujita if (dq != &hs->sc_sq)
60454004Sfujita (dq->dq_driver->d_start)(dq->dq_unit);
60554004Sfujita
60654004Sfujita return;
60754004Sfujita #endif
60854004Sfujita } else
60954004Sfujita goto abort;
61054004Sfujita
61154004Sfujita #ifndef NODISCONNECT
61254004Sfujita } else if (ints & INTS_RESEL) {
61354004Sfujita temp = hd->scsi_temp & ~(1 << SCSI_ID);
61454004Sfujita for (slave = 0; temp != 1; slave++) {
61554004Sfujita temp >>= 1;
61654004Sfujita }
61754004Sfujita
61854004Sfujita hd->scsi_ints = ints;
61954004Sfujita
62054004Sfujita scrschdl(ctlr, slave);
62154004Sfujita
62254004Sfujita dq = hs->sc_sq.dq_forw;
62354004Sfujita #ifdef DEBUGPRINT
62454004Sfujita dbgprintf("\n");
62554004Sfujita dbgprintf("scintr: RESELECT : ctlr = %d, slave = %d, cdb = %s\n",
62654004Sfujita dq->dq_ctlr, dq->dq_slave, scsi_command(dq->dq_cdb->cdb[0]));
62754004Sfujita #endif
62854004Sfujita #endif
62954004Sfujita } else if (ints & INTS_CMD_DONE) {
63054004Sfujita if (hs->sc_phase == BUS_FREE_PHASE)
63154004Sfujita goto abort;
63254004Sfujita else if (hs->sc_phase == MESG_IN_PHASE) {
63354004Sfujita hd->scsi_scmd = SCMD_RST_ACK;
63454004Sfujita
63554004Sfujita if ((hs->sc_msg[0] == MSG_CMD_COMPLETE) ||
63654004Sfujita (hs->sc_msg[0] == MSG_DISCONNECT)) {
63754004Sfujita hd->scsi_ints = ints;
63854004Sfujita
63954004Sfujita hs->sc_phase = BUS_FREE_PHASE;
64054004Sfujita
64154004Sfujita return;
64254004Sfujita }
64354004Sfujita }
64454004Sfujita if (hs->sc_flags & SC_SEL_TIMEOUT)
64554004Sfujita hs->sc_flags &= ~SC_SEL_TIMEOUT;
64654004Sfujita } else if (ints & INTS_SRV_REQ) {
64754004Sfujita if (hs->sc_phase != MESG_IN_PHASE)
64854004Sfujita goto abort;
64954004Sfujita } else if (ints & INTS_TIMEOUT) {
65054004Sfujita if (hs->sc_phase == ARB_SEL_PHASE) {
65154004Sfujita if (hs->sc_flags & SC_SEL_TIMEOUT) {
65254004Sfujita hd->scsi_ints = ints;
65354004Sfujita hs->sc_flags &= ~SC_SEL_TIMEOUT;
65454004Sfujita /* Such SCSI Device is not conected. */
65554004Sfujita
65654004Sfujita if (hs->sc_lock != NULL) {
65754004Sfujita *(hs->sc_lock) = SC_DEV_NOT_FOUND;
65854004Sfujita } else {
65954004Sfujita (dq->dq_driver->d_intr)(dq->dq_unit, SC_DEV_NOT_FOUND);
66054004Sfujita }
66154004Sfujita
66254004Sfujita return;
66354004Sfujita } else {
66454004Sfujita /* wait more 250 usec */
66554004Sfujita hs->sc_flags |= SC_SEL_TIMEOUT;
66654004Sfujita hd->scsi_temp = 0;
66754004Sfujita hd->scsi_tch = 0;
66854004Sfujita hd->scsi_tcm = 0x06;
66954004Sfujita hd->scsi_tcl = 0x40;
67054004Sfujita hd->scsi_ints = ints;
67154004Sfujita return;
67254004Sfujita }
67354004Sfujita } else
67454004Sfujita goto abort;
67554004Sfujita } else
67654004Sfujita goto abort;
67754004Sfujita
67854004Sfujita hd->scsi_ints = ints;
67954004Sfujita
68054004Sfujita /*
68154004Sfujita * Next SCSI Transfer
68254004Sfujita */
68354004Sfujita
68454004Sfujita wait = SC_TIMEOUT;
68554004Sfujita while ((hd->scsi_psns & PSNS_REQ) == 0) {
68654004Sfujita if (wait < 0) {
68754004Sfujita /* hd->scsi_scmd = SCMD_SET_ATN; */
68854004Sfujita hd->scsi_scmd = SCMD_RST;
68954004Sfujita DELAY(40); /* wait 25 micro sec */
69054004Sfujita hd->scsi_scmd = 0;
69154004Sfujita
69254004Sfujita wait = SC_TIMEOUT;
69354004Sfujita while (wait-- > 0)
69454004Sfujita DELAY(1);
69554004Sfujita
69654004Sfujita if (hs->sc_lock != NULL) {
69754004Sfujita *(hs->sc_lock) = SC_IO_TIMEOUT;
69854004Sfujita } else {
69954004Sfujita (dq->dq_driver->d_intr)(dq->dq_unit, SC_IO_TIMEOUT);
70054004Sfujita }
70154004Sfujita
70254004Sfujita return;
70354004Sfujita }
70454004Sfujita DELAY(1);
70554004Sfujita wait--;
70654004Sfujita }
70754004Sfujita
70854004Sfujita hs->sc_phase = hd->scsi_psns & PHASE;
70954004Sfujita
71054004Sfujita #ifdef DEBUGPRINT
71154004Sfujita dbgprintf("scintr: %s\n", phase_name(hs->sc_phase));
71254004Sfujita #endif
71354004Sfujita
71454004Sfujita if ((hs->sc_phase == DATA_OUT_PHASE) || (hs->sc_phase == DATA_IN_PHASE)) {
71554004Sfujita len = ( hs->sc_lock != NULL ? hs->sc_len : dq->dq_bp->b_bcount );
71654004Sfujita buf = ( hs->sc_lock != NULL ? hs->sc_buf : (u_char *) dq->dq_bp->b_un.b_addr );
71754004Sfujita } else if (hs->sc_phase == CMD_PHASE) {
71854004Sfujita len = ( hs->sc_lock != NULL ? hs->sc_cdblen : dq->dq_cdb->len );
71954004Sfujita buf = ( hs->sc_lock != NULL ? hs->sc_cdb : dq->dq_cdb->cdb );
72054004Sfujita } else if (hs->sc_phase == STATUS_PHASE) {
72154004Sfujita len = 1;
72254004Sfujita buf = &hs->sc_stat;
72354004Sfujita } else {
72454004Sfujita if (hs->sc_phase == MESG_OUT_PHASE) {
72554004Sfujita #ifndef NODISCONNECT
72654004Sfujita hs->sc_msg[0] = MSG_IDENTIFY_DR;
72754004Sfujita #else
72854004Sfujita hs->sc_msg[0] = MSG_IDENTIFY;
72954004Sfujita #endif
73054004Sfujita }
73154004Sfujita len = 1;
73254004Sfujita buf = hs->sc_msg;
73354004Sfujita }
73454004Sfujita
73554004Sfujita #ifdef XFER_ENABLE
73654004Sfujita if ((hs->sc_lock == NULL) && (hs->sc_phase == DATA_IN_PHASE)) {
73754004Sfujita dq->dq_xferp = buf;
73854004Sfujita dq->dq_xfercnt = len;
73954004Sfujita txfer_start(hd, len, hs->sc_phase);
74054004Sfujita return;
74154004Sfujita }
74254004Sfujita #endif
74354004Sfujita
74454004Sfujita ixfer_start(hd, len, hs->sc_phase);
74554004Sfujita if (hs->sc_phase & PHASE_IO) {
74654004Sfujita if ((wait = ixfer_in(hd, len, buf)) == -1) {
74754004Sfujita goto time_out;
74854004Sfujita }
74954004Sfujita if (dq->dq_imin == -1)
75054004Sfujita dq->dq_imin = wait;
75154004Sfujita else
75255175Saki dq->dq_imin = min(wait, dq->dq_imin);
75355175Saki dq->dq_imax = max(wait, dq->dq_imax);
75454004Sfujita } else {
75554004Sfujita if ((wait = ixfer_out(hd, len, buf)) == -1) {
75654004Sfujita goto time_out;
75754004Sfujita }
75854004Sfujita if (dq->dq_omin == -1)
75954004Sfujita dq->dq_omin = wait;
76054004Sfujita else
76155175Saki dq->dq_omin = min(wait, dq->dq_omin);
76255175Saki dq->dq_omax = max(wait, dq->dq_omax);
76354004Sfujita }
76454004Sfujita
76554004Sfujita return;
76654004Sfujita
76754004Sfujita time_out:
76854004Sfujita scabort(hs, hd);
76954004Sfujita printf("scintr: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x Current Status\n",
77054004Sfujita hd->scsi_ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns);
77154004Sfujita
77254004Sfujita if (hs->sc_lock != NULL) {
77354004Sfujita *(hs->sc_lock) = SC_IO_TIMEOUT;
77454004Sfujita } else {
77554004Sfujita (dq->dq_driver->d_intr)(dq->dq_unit, SC_IO_TIMEOUT);
77654004Sfujita }
77754004Sfujita
77854004Sfujita return;
77954004Sfujita
78054004Sfujita /*
78154004Sfujita * SCSI Abort
78254004Sfujita */
78354004Sfujita abort:
78454004Sfujita
78554004Sfujita /* SCSI IO failed */
78654004Sfujita scabort(hs, hd);
78754004Sfujita hd->scsi_ints = ints;
78854004Sfujita
78954004Sfujita if (hs->sc_lock != NULL) {
79054004Sfujita *(hs->sc_lock) = SC_IO_FAILED;
79154004Sfujita } else {
79254004Sfujita (dq->dq_driver->d_intr)(dq->dq_unit, SC_IO_FAILED);
79354004Sfujita }
79454004Sfujita
79554004Sfujita return;
79654004Sfujita }
79754004Sfujita
79854004Sfujita int
scabort(hs,hd)79954004Sfujita scabort(hs, hd)
800*65034Sakito register struct sc_softc *hs;
80154004Sfujita volatile register struct scsidevice *hd;
80254004Sfujita {
80354004Sfujita int len;
80454004Sfujita u_char junk;
80554004Sfujita
80654004Sfujita #ifdef DEBUGPRINT
80754004Sfujita dbgprintall();
80854004Sfujita printf("\n");
80954004Sfujita #endif
81054004Sfujita
81154004Sfujita printf("scabort: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x Current Status\n",
81254004Sfujita hd->scsi_ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns);
81354004Sfujita
81454004Sfujita if (hd->scsi_ints != 0)
81554004Sfujita hd->scsi_ints = hd->scsi_ints;
81654004Sfujita printf("scabort: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x Reset INTS reg.\n",
81754004Sfujita hd->scsi_ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns);
81854004Sfujita
81954004Sfujita if (hd->scsi_psns == 0 || (hd->scsi_ssts & SSTS_INITIATOR) == 0)
82054004Sfujita /* no longer connected to scsi target */
82154004Sfujita return;
82254004Sfujita
82354004Sfujita /* get the number of bytes remaining in current xfer + fudge */
82454004Sfujita len = (hd->scsi_tch << 16) | (hd->scsi_tcm << 8) | hd->scsi_tcl;
82554004Sfujita printf("scabort: Current xfer count = %d\n", len);
82654004Sfujita
82754004Sfujita /* for that many bus cycles, try to send an abort msg */
82854004Sfujita for (len += 1024; (hd->scsi_ssts & SSTS_INITIATOR) && --len >= 0; ) {
82954004Sfujita /*
83054004Sfujita hd->scsi_scmd = SCMD_SET_ATN;
83154004Sfujita printf("scabort: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x Set ATN\n",
83254004Sfujita hd->scsi_ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns);
83354004Sfujita */
83454004Sfujita while ((hd->scsi_psns & PSNS_REQ) == 0) {
83554004Sfujita printf("scabort: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x Wait for REQ\n",
83654004Sfujita hd->scsi_ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns);
83754004Sfujita if (! (hd->scsi_ssts & SSTS_INITIATOR))
83854004Sfujita goto out;
83954004Sfujita DELAY(1);
84054004Sfujita }
84154004Sfujita /*
84254004Sfujita if ((hd->scsi_psns & PHASE) == MESG_OUT_PHASE) {
84354004Sfujita hd->scsi_scmd = SCMD_RST_ATN;
84454004Sfujita printf("scabort: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x Reset ATN\n",
84554004Sfujita hd->scsi_ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns);
84654004Sfujita }
84754004Sfujita */
84854004Sfujita hd->scsi_pctl = hs->sc_phase = hd->scsi_psns & PHASE;
84954004Sfujita printf("scabort: Phase = %s\n", phase_name(hs->sc_phase));
85054004Sfujita
85154004Sfujita if (hd->scsi_psns & PHASE_IO) {
85254004Sfujita /* one of the input phases - read & discard a byte */
85354004Sfujita hd->scsi_scmd = SCMD_SET_ACK;
85454004Sfujita printf("scabort: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x Set ACK\n",
85554004Sfujita hd->scsi_ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns);
85654004Sfujita
85754004Sfujita while (hd->scsi_psns & PSNS_REQ) {
85854004Sfujita printf("scabort: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x Wait for REQ\n",
85954004Sfujita hd->scsi_ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns);
86054004Sfujita DELAY(1);
86154004Sfujita }
86254004Sfujita
86354004Sfujita junk = hd->scsi_temp;
86454004Sfujita printf("scabort: TEMP = 0x%s\n", hexstr(junk, 2));
86554004Sfujita } else {
86654004Sfujita /* one of the output phases - send an abort msg */
86754004Sfujita hd->scsi_temp = MSG_ABORT;
86854004Sfujita hd->scsi_scmd = SCMD_SET_ACK;
86954004Sfujita printf("scabort: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x Set ACK\n",
87054004Sfujita hd->scsi_ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns);
87154004Sfujita
87254004Sfujita while (hd->scsi_psns & PSNS_REQ) {
87354004Sfujita printf("scabort: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x Wait for REQ\n",
87454004Sfujita hd->scsi_ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns);
87554004Sfujita DELAY(1);
87654004Sfujita }
87754004Sfujita }
87854004Sfujita
87954004Sfujita hd->scsi_scmd = SCMD_RST_ACK;
88054004Sfujita printf("scabort: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x Reset ACK\n",
88154004Sfujita hd->scsi_ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns);
88254004Sfujita }
88354004Sfujita out:
88454004Sfujita /*
88554004Sfujita * Either the abort was successful & the bus is disconnected or
88654004Sfujita * the device didn't listen. If the latter, announce the problem.
88754004Sfujita * Either way, reset the card & the SPC.
88854004Sfujita */
88954004Sfujita if (len < 0 && hs)
89054004Sfujita printf("sc%d: abort failed. phase=0x%x, ssts=0x%x\n",
89154004Sfujita hs->sc_hc->hp_unit, hd->scsi_psns, hd->scsi_ssts);
89254004Sfujita
89354004Sfujita while (hd->scsi_ints == 0)
89454004Sfujita DELAY(1);
89554004Sfujita
89654004Sfujita hd->scsi_ints = hd->scsi_ints;
89754004Sfujita
89854004Sfujita printf("scintr: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x Current Status\n",
89954004Sfujita hd->scsi_ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns);
90054004Sfujita
90154004Sfujita printf("scabort: SCSI abort operation is done\n");
90254004Sfujita }
90354004Sfujita
90454004Sfujita
90554004Sfujita /*
90654004Sfujita * SPC device queue handling
90754004Sfujita */
90854004Sfujita
90954004Sfujita int
screq(dq)91054004Sfujita screq(dq)
91154004Sfujita register struct scsi_queue *dq;
91254004Sfujita {
913*65034Sakito register struct sc_softc *hs = &sc_softc[dq->dq_ctlr];
91454004Sfujita register struct scsi_queue *hq = &hs->sc_sq;
91554004Sfujita
91654004Sfujita insque(dq, hq->dq_back);
91754004Sfujita
91854004Sfujita if (dq->dq_back == hq) {
91954004Sfujita #ifdef QUE_DEBUG
92054004Sfujita printf("screq: slave = %d, command = %s\n",
92154004Sfujita hq->dq_forw->dq_slave,
92254004Sfujita scsi_command(hq->dq_forw->dq_cdb->cdb[0]));
92354004Sfujita #endif
92454004Sfujita return(1);
92554004Sfujita }
92654004Sfujita
92754004Sfujita return(0);
92854004Sfujita }
92954004Sfujita
93054004Sfujita #ifndef NODISCONNECT
93154004Sfujita int
scpend(dq)93254004Sfujita scpend(dq)
93354004Sfujita register struct scsi_queue *dq;
93454004Sfujita {
935*65034Sakito register struct sc_softc *hs = &sc_softc[dq->dq_ctlr];
93654004Sfujita register struct scsi_queue *hq = &hs->sc_sq;
93754004Sfujita register struct scsi_queue *wq = &hs->sc_wq;
93854004Sfujita
93954004Sfujita remque(dq);
94054004Sfujita
94154004Sfujita insque(dq, wq->dq_back);
94254004Sfujita }
94354004Sfujita
94454004Sfujita int
scrschdl(ctlr,slave)94554004Sfujita scrschdl(ctlr, slave)
94654004Sfujita register int ctlr;
94754004Sfujita register int slave;
94854004Sfujita {
949*65034Sakito register struct sc_softc *hs = &sc_softc[ctlr];
95054004Sfujita register struct scsi_queue *wq = &hs->sc_wq;
95154004Sfujita register struct scsi_queue *hq = &hs->sc_sq;
95254004Sfujita register struct scsi_queue *dq;
95354004Sfujita
95454004Sfujita for (dq = wq->dq_forw; dq != wq; dq = dq->dq_forw) {
95554004Sfujita if (dq->dq_slave == slave)
95654004Sfujita goto found;
95754004Sfujita }
95854004Sfujita
95954004Sfujita return(0);
96054004Sfujita
96154004Sfujita found:
96254004Sfujita remque(dq);
96354004Sfujita insque(dq, hq);
96454004Sfujita
96554004Sfujita return(1);
96654004Sfujita }
96754004Sfujita #endif
96854004Sfujita
96954004Sfujita int
scfree(dq)97054004Sfujita scfree(dq)
97154004Sfujita register struct scsi_queue *dq;
97254004Sfujita {
973*65034Sakito register struct sc_softc *hs = &sc_softc[dq->dq_ctlr];
97454004Sfujita register struct scsi_queue *hq = &hs->sc_sq;
97554004Sfujita int status = hs->sc_stat;
97654004Sfujita
97754004Sfujita remque(dq);
97854004Sfujita
97954004Sfujita hs->sc_flags = 0;
98054004Sfujita hs->sc_phase = BUS_FREE_PHASE;
98154004Sfujita
98254004Sfujita hs->sc_stat = 0;
98354004Sfujita hs->sc_msg[0] = 0;
98454004Sfujita
98554004Sfujita if ((dq = hq->dq_forw) != hq) {
98654004Sfujita #ifdef QUE_DEBUG
98754004Sfujita printf("scfree: slave = %d, command = %s\n",
98854004Sfujita dq->dq_slave,
98954004Sfujita scsi_command(dq->dq_cdb->cdb[0]));
99054004Sfujita #endif
99154004Sfujita (dq->dq_driver->d_start)(dq->dq_unit);
99254004Sfujita }
99354004Sfujita
99454004Sfujita return(status);
99554004Sfujita }
99654004Sfujita
99754004Sfujita /*
99854004Sfujita * SCSI common interface
99954004Sfujita */
100054004Sfujita
100154004Sfujita int scsi_lock[NSC];
100254004Sfujita
100354004Sfujita int
scsi_result(unit,stat)100454004Sfujita scsi_result(unit, stat)
100554004Sfujita int unit, stat;
100654004Sfujita {
100754004Sfujita #ifdef SCSI_DEBUG
100854004Sfujita printf("scsi_result: stat = %s\n", scsi_status(stat));
100954004Sfujita #endif
101054004Sfujita if (stat < 0)
101154004Sfujita scsi_lock[unit] = stat;
101254004Sfujita else
101354004Sfujita scsi_lock[unit] = SC_IO_COMPLETE;
101454004Sfujita }
101554004Sfujita
101654004Sfujita struct driver scsi_driver = {
101754004Sfujita (int (*)()) 0, "scsi", (int (*)()) 0, (int (*)()) 0, scsi_result, (int (*)()) 0
101854004Sfujita };
101954004Sfujita
102054004Sfujita struct scsi_queue scsi_entry[NSC];
102154004Sfujita
102254004Sfujita int
scsi_immed_command(ctlr,slave,lun,cdb,buf,len)102354004Sfujita scsi_immed_command(ctlr, slave, lun, cdb, buf, len)
102454004Sfujita int ctlr, slave, lun;
102554004Sfujita struct scsi_fmt_cdb *cdb;
102654004Sfujita u_char *buf;
102754004Sfujita unsigned len;
102854004Sfujita {
1029*65034Sakito register struct sc_softc *hs = &sc_softc[ctlr];
103054004Sfujita volatile register struct scsidevice *hd =
103154004Sfujita (struct scsidevice *) hs->sc_hc->hp_addr;
103254004Sfujita register struct scsi_queue *dq = &scsi_entry[ctlr];
103354004Sfujita register struct buf *bp;
103454004Sfujita int s, status, wait = 30;
103554004Sfujita
103654004Sfujita #ifdef SCSI_DEBUG
103754004Sfujita printf("scsi_immed_command( %d, %d, %d, cdb(%d,%s), buf, %d): Start\n",
103854004Sfujita ctlr, slave, lun, cdb->len, scsi_command(cdb->cdb[0]), len);
103954004Sfujita #endif
104057057Sakito bp = geteblk(len);
104157057Sakito bp->b_flags = B_BUSY;
104254004Sfujita
104354004Sfujita s = splbio();
104454004Sfujita
104554004Sfujita dq->dq_unit = ctlr;
104654004Sfujita dq->dq_ctlr = ctlr;
104754004Sfujita dq->dq_slave = slave;
104854004Sfujita dq->dq_driver = &scsi_driver;
104954004Sfujita dq->dq_cdb = cdb;
105054004Sfujita dq->dq_bp = bp;
105154004Sfujita
105254004Sfujita scsi_lock[ctlr] = SC_IN_PROGRESS;
105354004Sfujita if (screq(dq))
105454004Sfujita scstart(ctlr);
105554004Sfujita
105654004Sfujita splx(s);
105754004Sfujita
105854004Sfujita while (scsi_lock[ctlr] == SC_IN_PROGRESS) {
105954004Sfujita if (wait < 0) {
106054004Sfujita scabort(hs, hd);
106154004Sfujita
106254004Sfujita s = splbio();
106354004Sfujita status = scfree(dq);
106454004Sfujita splx(s);
106554004Sfujita
106654004Sfujita bp->b_flags = 0;
106754004Sfujita
106854004Sfujita return(SC_IO_FAILED);
106954004Sfujita }
107054004Sfujita
107154004Sfujita DELAY(100000);
107254004Sfujita wait--;
107354004Sfujita }
107454004Sfujita
107554004Sfujita s = splbio();
107654004Sfujita status = scfree(dq);
107754004Sfujita splx(s);
107854004Sfujita
107954004Sfujita if (scsi_lock[ctlr] < 0)
108054004Sfujita status = scsi_lock[ctlr];
108154004Sfujita
108257057Sakito bcopy(bp->b_un.b_addr, buf, len);
108354004Sfujita
108457057Sakito brelse(bp);
108557057Sakito
108654004Sfujita #ifdef SCSI_DEBUG
108754004Sfujita printf("scsi_immed_command: Status -- 0x%x\n", status);
108854004Sfujita #endif
108954004Sfujita return(status);
109054004Sfujita }
109154004Sfujita
109254004Sfujita int
sc_test_unit_rdy(ctlr,slave,lun)1093*65034Sakito sc_test_unit_rdy(ctlr, slave, lun)
109454004Sfujita int ctlr, slave, lun;
109554004Sfujita {
109654004Sfujita static struct scsi_fmt_cdb cdb = { 6, CMD_TEST_UNIT_READY };
109754004Sfujita int stat;
109854004Sfujita
109954004Sfujita while ((stat = scsi_immed_command(ctlr, slave, lun,
110054004Sfujita &cdb, (u_char *) 0, 0)) == SC_BUSY) {
110154004Sfujita DELAY(10000);
110254004Sfujita }
110354004Sfujita
110454004Sfujita return(stat);
110554004Sfujita }
110654004Sfujita
110754004Sfujita int
sc_request_sense(ctlr,slave,lun,buf,len)1108*65034Sakito sc_request_sense(ctlr, slave, lun, buf, len)
110954004Sfujita int ctlr, slave, lun;
111054004Sfujita u_char *buf;
111154004Sfujita unsigned len;
111254004Sfujita {
1113*65034Sakito register struct sc_softc *hs = &sc_softc[ctlr];
111454004Sfujita volatile register struct scsidevice *hd =
111554004Sfujita (struct scsidevice *) hs->sc_hc->hp_addr;
111654004Sfujita static struct scsi_fmt_cdb req_cmd = { 6, CMD_REQUEST_SENSE };
111754004Sfujita int s, status, lock;
111854004Sfujita
111954004Sfujita #ifdef REQ_DEBUG
1120*65034Sakito printf("sc_request_sense( %d, %d, %d, buf, %d) -- Start\n",
112154004Sfujita ctlr, slave, lun, len);
112254004Sfujita #endif
112354004Sfujita
112454004Sfujita req_cmd.cdb[1] = lun;
112554004Sfujita req_cmd.cdb[4] = len;
112654004Sfujita
112754004Sfujita if (hd->scsi_ssts & (SSTS_INITIATOR|SSTS_TARGET|SSTS_BUSY))
112854004Sfujita return(0);
112954004Sfujita
113054004Sfujita s = splbio();
113154004Sfujita
113254004Sfujita hs->sc_flags = 0;
113354004Sfujita hs->sc_phase = ARB_SEL_PHASE;
113454004Sfujita
113554004Sfujita hs->sc_cdb = req_cmd.cdb;
113654004Sfujita hs->sc_cdblen = req_cmd.len;
113754004Sfujita hs->sc_buf = buf;
113854004Sfujita hs->sc_len = len;
113954004Sfujita
114054004Sfujita hs->sc_stat = 0;
114154004Sfujita hs->sc_msg[0] = 0;
114254004Sfujita
114354004Sfujita lock = SC_IN_PROGRESS;
114454004Sfujita hs->sc_lock = &lock;
114554004Sfujita
114654004Sfujita issue_select(hd, slave, 0);
114754004Sfujita
114854004Sfujita spl0();
114954004Sfujita
115054004Sfujita while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED))
115154004Sfujita DELAY(10);
115254004Sfujita
115354004Sfujita splbio();
115454004Sfujita
115554004Sfujita hs->sc_flags = 0;
115654004Sfujita hs->sc_phase = BUS_FREE_PHASE;
115754004Sfujita
115854004Sfujita hs->sc_cdb = NULL;
115954004Sfujita hs->sc_cdblen = 0;
116054004Sfujita hs->sc_buf = NULL;
116154004Sfujita hs->sc_len = 0;
116254004Sfujita hs->sc_lock = NULL;
116354004Sfujita
116454004Sfujita status = hs->sc_stat;
116554004Sfujita
116654004Sfujita hs->sc_stat = 0;
116754004Sfujita hs->sc_msg[0] = 0;
116854004Sfujita
116954004Sfujita splx(s);
117054004Sfujita
117154004Sfujita if (lock == SC_IO_COMPLETE) {
117254004Sfujita #ifdef REQ_DEBUG
1173*65034Sakito printf("sc_request_sense: Status -- 0x%x\n", status);
117454004Sfujita #endif
117554004Sfujita return(status);
117654004Sfujita } else {
117754004Sfujita return(lock);
117854004Sfujita }
117954004Sfujita }
118054004Sfujita #endif
1181