Annotation of sys/arch/hp300/stand/common/scsi.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: scsi.c,v 1.6 2006/08/17 06:31:10 miod Exp $ */
2: /* $NetBSD: scsi.c,v 1.7 1997/01/30 10:32:57 thorpej Exp $ */
3:
4: /*
5: * This is reported to fix some odd failures when disklabeling
6: * SCSI disks in SYS_INST.
7: */
8: #define SLOWSCSI
9:
10: /*
11: * Copyright (c) 1988 University of Utah.
12: * Copyright (c) 1990, 1993
13: * The Regents of the University of California. All rights reserved.
14: *
15: * This code is derived from software contributed to Berkeley by
16: * Van Jacobson of Lawrence Berkeley Laboratory and the Systems
17: * Programming Group of the University of Utah Computer Science Department.
18: *
19: * Redistribution and use in source and binary forms, with or without
20: * modification, are permitted provided that the following conditions
21: * are met:
22: * 1. Redistributions of source code must retain the above copyright
23: * notice, this list of conditions and the following disclaimer.
24: * 2. Redistributions in binary form must reproduce the above copyright
25: * notice, this list of conditions and the following disclaimer in the
26: * documentation and/or other materials provided with the distribution.
27: * 3. Neither the name of the University nor the names of its contributors
28: * may be used to endorse or promote products derived from this software
29: * without specific prior written permission.
30: *
31: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
32: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
35: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
40: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41: * SUCH DAMAGE.
42: *
43: * from: Utah $Hdr: scsi.c 1.3 90/01/27$
44: *
45: * @(#)scsi.c 8.1 (Berkeley) 6/10/93
46: */
47:
48: /*
49: * SCSI bus driver for standalone programs.
50: */
51:
52: #include <sys/param.h>
53: #include <sys/reboot.h>
54:
55: #include <lib/libsa/stand.h>
56:
57: #include "samachdep.h"
58: #include "device.h"
59: #include "scsireg.h"
60: #include "scsivar.h"
61:
62: struct scsi_softc scsi_softc[NSCSI];
63:
64: int scsi_cmd_wait = 50000; /* use the "real" driver init_wait value */
65: int scsi_data_wait = 50000; /* use the "real" driver init_wait value */
66:
67: void scsiabort(struct scsi_softc *, volatile struct scsidevice *);
68: void scsireset(int);
69: int scsi_request_sense(int, int, u_char *, u_int);
70:
71: void
72: scsiinit()
73: {
74: extern struct hp_hw sc_table[];
75: struct hp_hw *hw;
76: struct scsi_softc *hs;
77: int i;
78: static int waitset = 0;
79:
80: i = 0;
81: for (hw = sc_table; i < NSCSI && hw < &sc_table[MAXCTLRS]; hw++) {
82: if (!HW_ISSCSI(hw))
83: continue;
84: hs = &scsi_softc[i];
85: hs->sc_addr = hw->hw_kva;
86: scsireset(i);
87: if (howto & RB_ASKNAME)
88: printf("scsi%d at sc%d\n", i, hw->hw_sc);
89: hw->hw_pa = (caddr_t) i; /* XXX for autoconfig */
90: hs->sc_alive = 1;
91: i++;
92: }
93: /*
94: * Adjust the wait values
95: */
96: if (!waitset) {
97: scsi_cmd_wait *= cpuspeed;
98: scsi_data_wait *= cpuspeed;
99: waitset = 1;
100: }
101: }
102:
103: int
104: scsialive(int unit)
105: {
106: if (unit >= NSCSI || scsi_softc[unit].sc_alive == 0)
107: return (0);
108: return (1);
109: }
110:
111: void
112: scsireset(int unit)
113: {
114: volatile struct scsidevice *hd;
115: struct scsi_softc *hs;
116: u_int i;
117:
118: hs = &scsi_softc[unit];
119: hd = (struct scsidevice *)hs->sc_addr;
120: hd->scsi_id = 0xFF;
121: DELAY(100);
122: /*
123: * Disable interrupts then reset the FUJI chip.
124: */
125: hd->scsi_csr = 0;
126: hd->scsi_sctl = SCTL_DISABLE | SCTL_CTRLRST;
127: hd->scsi_scmd = 0;
128: hd->scsi_tmod = 0;
129: hd->scsi_pctl = 0;
130: hd->scsi_temp = 0;
131: hd->scsi_tch = 0;
132: hd->scsi_tcm = 0;
133: hd->scsi_tcl = 0;
134: hd->scsi_ints = 0;
135:
136: /*
137: * Configure the FUJI chip with its SCSI address, all
138: * interrupts enabled & appropriate parity.
139: */
140: i = (~hd->scsi_hconf) & 0x7;
141: hs->sc_scsi_addr = 1 << i;
142: hd->scsi_bdid = i;
143: if (hd->scsi_hconf & HCONF_PARITY)
144: hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB |
145: SCTL_SEL_ENAB | SCTL_RESEL_ENAB |
146: SCTL_INTR_ENAB | SCTL_PARITY_ENAB;
147: else
148: hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB |
149: SCTL_SEL_ENAB | SCTL_RESEL_ENAB |
150: SCTL_INTR_ENAB;
151: hd->scsi_sctl &=~ SCTL_DISABLE;
152: }
153:
154:
155: void
156: scsiabort(struct scsi_softc *hs, volatile struct scsidevice *hd)
157: {
158: printf("scsi%d error: scsiabort\n", (int)(hs - scsi_softc));
159:
160: scsireset(hs - scsi_softc);
161: DELAY(1000000);
162: }
163:
164: static int
165: issue_select(volatile struct scsidevice *hd, u_char target, u_char our_addr)
166: {
167: if (hd->scsi_ssts & (SSTS_INITIATOR|SSTS_TARGET|SSTS_BUSY))
168: return (1);
169:
170: if (hd->scsi_ints & INTS_DISCON)
171: hd->scsi_ints = INTS_DISCON;
172:
173: hd->scsi_pctl = 0;
174: hd->scsi_temp = (1 << target) | our_addr;
175: /* select timeout is hardcoded to 2ms */
176: hd->scsi_tch = 0;
177: hd->scsi_tcm = 32;
178: hd->scsi_tcl = 4;
179:
180: hd->scsi_scmd = SCMD_SELECT;
181: return (0);
182: }
183:
184: static int
185: wait_for_select(volatile struct scsidevice *hd)
186: {
187: int wait;
188: u_char ints;
189:
190: wait = scsi_data_wait;
191: while ((ints = hd->scsi_ints) == 0) {
192: if (--wait < 0)
193: return (1);
194: DELAY(1);
195: }
196: hd->scsi_ints = ints;
197: return (!(hd->scsi_ssts & SSTS_INITIATOR));
198: }
199:
200: static int
201: ixfer_start(volatile struct scsidevice *hd, int len, u_char phase, int wait)
202: {
203:
204: hd->scsi_tch = len >> 16;
205: hd->scsi_tcm = len >> 8;
206: hd->scsi_tcl = len;
207: hd->scsi_pctl = phase;
208: hd->scsi_tmod = 0; /*XXX*/
209: hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR;
210:
211: /* wait for xfer to start or svc_req interrupt */
212: while ((hd->scsi_ssts & SSTS_BUSY) == 0) {
213: if (hd->scsi_ints || --wait < 0)
214: return (0);
215: DELAY(1);
216: }
217: return (1);
218: }
219:
220: static int
221: ixfer_out(volatile struct scsidevice *hd, int len, u_char *buf)
222: {
223: int wait = scsi_data_wait;
224:
225: for (; len > 0; --len) {
226: while (hd->scsi_ssts & SSTS_DREG_FULL) {
227: if (hd->scsi_ints || --wait < 0)
228: return (len);
229: DELAY(1);
230: }
231: hd->scsi_dreg = *buf++;
232: }
233: return (0);
234: }
235:
236: static int
237: ixfer_in(volatile struct scsidevice *hd, int len, u_char *buf)
238: {
239: int wait = scsi_data_wait;
240:
241: for (; len > 0; --len) {
242: while (hd->scsi_ssts & SSTS_DREG_EMPTY) {
243: if (hd->scsi_ints || --wait < 0) {
244: while (! (hd->scsi_ssts & SSTS_DREG_EMPTY)) {
245: *buf++ = hd->scsi_dreg;
246: --len;
247: }
248: return (len);
249: }
250: DELAY(1);
251: }
252: *buf++ = hd->scsi_dreg;
253: }
254: return (len);
255: }
256:
257: static int
258: scsiicmd(struct scsi_softc *hs, int target, u_char *cbuf, int clen, u_char *buf,
259: int len, u_char xferphase)
260: {
261: volatile struct scsidevice *hd = (struct scsidevice *)hs->sc_addr;
262: u_char phase, ints;
263: int wait;
264:
265: /* select the SCSI bus (it's an error if bus isn't free) */
266: if (issue_select(hd, target, hs->sc_scsi_addr))
267: return (-2);
268: if (wait_for_select(hd))
269: return (-2);
270: /*
271: * Wait for a phase change (or error) then let the device
272: * sequence us through the various SCSI phases.
273: */
274: hs->sc_stat = -1;
275: phase = CMD_PHASE;
276: while (1) {
277: wait = scsi_cmd_wait;
278: switch (phase) {
279:
280: case CMD_PHASE:
281: if (ixfer_start(hd, clen, phase, wait))
282: if (ixfer_out(hd, clen, cbuf))
283: goto abort;
284: phase = xferphase;
285: break;
286:
287: case DATA_IN_PHASE:
288: if (len <= 0)
289: goto abort;
290: wait = scsi_data_wait;
291: if (ixfer_start(hd, len, phase, wait) ||
292: !(hd->scsi_ssts & SSTS_DREG_EMPTY))
293: ixfer_in(hd, len, buf);
294: phase = STATUS_PHASE;
295: break;
296:
297: case DATA_OUT_PHASE:
298: if (len <= 0)
299: goto abort;
300: wait = scsi_data_wait;
301: if (ixfer_start(hd, len, phase, wait))
302: if (ixfer_out(hd, len, buf))
303: goto abort;
304: phase = STATUS_PHASE;
305: break;
306:
307: case STATUS_PHASE:
308: wait = scsi_data_wait;
309: if (ixfer_start(hd, sizeof(hs->sc_stat), phase, wait) ||
310: !(hd->scsi_ssts & SSTS_DREG_EMPTY))
311: ixfer_in(hd, sizeof(hs->sc_stat), &hs->sc_stat);
312: phase = MESG_IN_PHASE;
313: break;
314:
315: case MESG_IN_PHASE:
316: if (ixfer_start(hd, sizeof(hs->sc_msg), phase, wait) ||
317: !(hd->scsi_ssts & SSTS_DREG_EMPTY)) {
318: ixfer_in(hd, sizeof(hs->sc_msg),
319: (u_char *)&hs->sc_msg);
320: hd->scsi_scmd = SCMD_RST_ACK;
321: }
322: phase = BUS_FREE_PHASE;
323: break;
324:
325: case BUS_FREE_PHASE:
326: goto out;
327:
328: default:
329: printf("scsi%d: unexpected scsi phase %d\n",
330: (int)(hs - scsi_softc), phase);
331: goto abort;
332: }
333: #ifdef SLOWSCSI
334: /*
335: * XXX we have weird transient problems with booting from
336: * slow scsi disks on fast machines. I have never been
337: * able to pin the problem down, but a large delay here
338: * seems to always work.
339: */
340: DELAY(1000);
341: #endif
342: /* wait for last command to complete */
343: while ((ints = hd->scsi_ints) == 0) {
344: if (--wait < 0)
345: goto abort;
346: DELAY(1);
347: }
348: hd->scsi_ints = ints;
349: if (ints & INTS_SRV_REQ)
350: phase = hd->scsi_psns & PHASE;
351: else if (ints & INTS_DISCON)
352: goto out;
353: else if ((ints & INTS_CMD_DONE) == 0)
354: goto abort;
355: }
356: abort:
357: scsiabort(hs, hd);
358: out:
359: return (hs->sc_stat);
360: }
361:
362: int
363: scsi_test_unit_rdy(int ctlr, int slave)
364: {
365: struct scsi_softc *hs = &scsi_softc[ctlr];
366: static struct scsi_cdb6 cdb = { CMD_TEST_UNIT_READY };
367:
368: return (scsiicmd(hs, slave, (u_char *)&cdb, sizeof(cdb),
369: (u_char *)0, 0, STATUS_PHASE));
370: }
371:
372: int
373: scsi_request_sense(int ctlr, int slave, u_char *buf, u_int len)
374: {
375: struct scsi_softc *hs = &scsi_softc[ctlr];
376: static struct scsi_cdb6 cdb = { CMD_REQUEST_SENSE };
377:
378: cdb.len = len;
379: return (scsiicmd(hs, slave, (u_char *)&cdb, sizeof(cdb),
380: buf, len, DATA_IN_PHASE));
381: }
382:
383: int
384: scsi_read_capacity(int ctlr, int slave, u_char *buf, u_int len)
385: {
386: struct scsi_softc *hs = &scsi_softc[ctlr];
387: static struct scsi_cdb10 cdb = { CMD_READ_CAPACITY };
388:
389: return (scsiicmd(hs, slave, (u_char *)&cdb, sizeof(cdb),
390: buf, len, DATA_IN_PHASE));
391: }
392:
393: int
394: scsi_tt_read(int ctlr, int slave, u_char *buf, u_int len, daddr_t blk,
395: u_int nblk)
396: {
397: struct scsi_softc *hs = &scsi_softc[ctlr];
398: struct scsi_cdb10 cdb;
399:
400: bzero(&cdb, sizeof(cdb));
401: cdb.cmd = CMD_READ_EXT;
402: cdb.lbah = blk >> 24;
403: cdb.lbahm = blk >> 16;
404: cdb.lbalm = blk >> 8;
405: cdb.lbal = blk;
406: cdb.lenh = nblk >> (8 + DEV_BSHIFT);
407: cdb.lenl = nblk >> DEV_BSHIFT;
408: return (scsiicmd(hs, slave, (u_char *)&cdb, sizeof(cdb),
409: buf, len, DATA_IN_PHASE));
410: }
411:
412: int
413: scsi_tt_write(int ctlr, int slave, u_char *buf, u_int len, daddr_t blk,
414: u_int nblk)
415: {
416: struct scsi_softc *hs = &scsi_softc[ctlr];
417: struct scsi_cdb10 cdb;
418:
419: bzero(&cdb, sizeof(cdb));
420: cdb.cmd = CMD_WRITE_EXT;
421: cdb.lbah = blk >> 24;
422: cdb.lbahm = blk >> 16;
423: cdb.lbalm = blk >> 8;
424: cdb.lbal = blk;
425: cdb.lenh = nblk >> (8 + DEV_BSHIFT);
426: cdb.lenl = nblk >> DEV_BSHIFT;
427: return (scsiicmd(hs, slave, (u_char *)&cdb, sizeof(cdb),
428: buf, len, DATA_OUT_PHASE));
429: }
CVSweb