xref: /original-bsd/sys/hp300/stand/scsi.c (revision 331bfa8d)
1 /*
2  * Copyright (c) 1988 University of Utah.
3  * Copyright (c) 1990 The Regents of the University of California.
4  * All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * Van Jacobson of Lawrence Berkeley Laboratory and the Systems
8  * Programming Group of the University of Utah Computer Science Department.
9  *
10  * %sccs.include.redist.c%
11  *
12  * from: Utah $Hdr: scsi.c 1.3 90/01/27$
13  *
14  *	@(#)scsi.c	7.2 (Berkeley) 12/16/90
15  */
16 
17 /*
18  * SCSI bus driver for standalone programs.
19  */
20 
21 #include "sys/types.h"
22 #include "sys/reboot.h"
23 #include "../dev/device.h"
24 #include "../dev/scsireg.h"
25 #include "scsivar.h"
26 
27 #include "saio.h"
28 #include "samachdep.h"
29 
30 struct	scsi_softc scsi_softc[NSCSI];
31 
32 #define	scsiunit(x)	((x) >> 3)
33 #define	scsislave(x)	((x) & 7)
34 
35 void scsireset();
36 int scsi_cmd_wait = 500;
37 int scsi_data_wait = 300000;
38 
39 scsiinit()
40 {
41 	extern struct hp_hw sc_table[];
42 	register struct hp_hw *hw;
43 	register struct scsi_softc *hs;
44 	register int i, addr;
45 	static int first = 1;
46 
47 	i = 0;
48 	for (hw = sc_table; i < NSCSI && hw < &sc_table[MAX_CTLR]; hw++) {
49 		if (hw->hw_type != SCSI)
50 			continue;
51 		hs = &scsi_softc[i];
52 		hs->sc_addr = hw->hw_addr;
53 		scsireset(i);
54 		if (howto & RB_ASKNAME)
55 			printf("scsi%d at sc%d\n", i, hw->hw_sc);
56 		/*
57 		 * Adjust devtype on first call.  This routine assumes that
58 		 * adaptor is in the high byte of devtype.
59 		 */
60 		if (first && ((devtype >> 24) & 0xff) == hw->hw_sc) {
61 			devtype = (devtype & 0x00ffffff) | (i << 24);
62 			first = 0;
63 		}
64 		hs->sc_alive = 1;
65 		i++;
66 	}
67 }
68 
69 scsialive(unit)
70 	register int unit;
71 {
72 	unit = scsiunit(unit);
73 	if (unit >= NSCSI || scsi_softc[unit].sc_alive == 0)
74 		return (0);
75 	return (1);
76 }
77 
78 void
79 scsireset(unit)
80 	register int unit;
81 {
82 	volatile register struct scsidevice *hd;
83 	register struct scsi_softc *hs;
84 	u_int i;
85 
86 	unit = scsiunit(unit);
87 	hs = &scsi_softc[unit];
88 	hd = (struct scsidevice *)hs->sc_addr;
89 	hd->scsi_id = 0xFF;
90 	DELAY(100);
91 	/*
92 	 * Disable interrupts then reset the FUJI chip.
93 	 */
94 	hd->scsi_csr  = 0;
95 	hd->scsi_sctl = SCTL_DISABLE | SCTL_CTRLRST;
96 	hd->scsi_scmd = 0;
97 	hd->scsi_tmod = 0;
98 	hd->scsi_pctl = 0;
99 	hd->scsi_temp = 0;
100 	hd->scsi_tch  = 0;
101 	hd->scsi_tcm  = 0;
102 	hd->scsi_tcl  = 0;
103 	hd->scsi_ints = 0;
104 
105 	/*
106 	 * Configure the FUJI chip with its SCSI address, all
107 	 * interrupts enabled & appropriate parity.
108 	 */
109 	i = (~hd->scsi_hconf) & 0x7;
110 	hs->sc_scsi_addr = 1 << i;
111 	hd->scsi_bdid = i;
112 	if (hd->scsi_hconf & HCONF_PARITY)
113 		hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB |
114 				SCTL_SEL_ENAB | SCTL_RESEL_ENAB |
115 				SCTL_INTR_ENAB | SCTL_PARITY_ENAB;
116 	else
117 		hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB |
118 				SCTL_SEL_ENAB | SCTL_RESEL_ENAB |
119 				SCTL_INTR_ENAB;
120 	hd->scsi_sctl &=~ SCTL_DISABLE;
121 }
122 
123 
124 int
125 scsiabort(hs, hd)
126 	register struct scsi_softc *hs;
127 	volatile register struct scsidevice *hd;
128 {
129 	printf("scsi error: scsiabort\n");
130 	return (0);
131 }
132 
133 static int
134 issue_select(hd, target, our_addr)
135 	volatile register struct scsidevice *hd;
136 	u_char target, our_addr;
137 {
138 	if (hd->scsi_ssts & (SSTS_INITIATOR|SSTS_TARGET|SSTS_BUSY))
139 		return (1);
140 
141 	if (hd->scsi_ints & INTS_DISCON)
142 		hd->scsi_ints = INTS_DISCON;
143 
144 	hd->scsi_pctl = 0;
145 	hd->scsi_temp = (1 << target) | our_addr;
146 	/* select timeout is hardcoded to 2ms */
147 	hd->scsi_tch = 0;
148 	hd->scsi_tcm = 32;
149 	hd->scsi_tcl = 4;
150 
151 	hd->scsi_scmd = SCMD_SELECT;
152 	return (0);
153 }
154 
155 static int
156 wait_for_select(hd)
157 	volatile register struct scsidevice *hd;
158 {
159 	u_char ints;
160 
161 	while ((ints = hd->scsi_ints) == 0)
162 		DELAY(1);
163 	hd->scsi_ints = ints;
164 	return (!(hd->scsi_ssts & SSTS_INITIATOR));
165 }
166 
167 static int
168 ixfer_start(hd, len, phase, wait)
169 	volatile register struct scsidevice *hd;
170 	int len;
171 	u_char phase;
172 	register int wait;
173 {
174 
175 	hd->scsi_tch = len >> 16;
176 	hd->scsi_tcm = len >> 8;
177 	hd->scsi_tcl = len;
178 	hd->scsi_pctl = phase;
179 	hd->scsi_tmod = 0; /*XXX*/
180 	hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR;
181 
182 	/* wait for xfer to start or svc_req interrupt */
183 	while ((hd->scsi_ssts & SSTS_BUSY) == 0) {
184 		if (hd->scsi_ints || --wait < 0)
185 			return (0);
186 		DELAY(1);
187 	}
188 	return (1);
189 }
190 
191 static int
192 ixfer_out(hd, len, buf)
193 	volatile register struct scsidevice *hd;
194 	int len;
195 	register u_char *buf;
196 {
197 	register int wait = scsi_data_wait;
198 
199 	for (; len > 0; --len) {
200 		while (hd->scsi_ssts & SSTS_DREG_FULL) {
201 			if (hd->scsi_ints || --wait < 0)
202 				return (len);
203 			DELAY(1);
204 		}
205 		hd->scsi_dreg = *buf++;
206 	}
207 	return (0);
208 }
209 
210 static int
211 ixfer_in(hd, len, buf)
212 	volatile register struct scsidevice *hd;
213 	int len;
214 	register u_char *buf;
215 {
216 	register int wait = scsi_data_wait;
217 
218 	for (; len > 0; --len) {
219 		while (hd->scsi_ssts & SSTS_DREG_EMPTY) {
220 			if (hd->scsi_ints || --wait < 0) {
221 				while (! (hd->scsi_ssts & SSTS_DREG_EMPTY)) {
222 					*buf++ = hd->scsi_dreg;
223 					--len;
224 				}
225 				return (len);
226 			}
227 			DELAY(1);
228 		}
229 		*buf++ = hd->scsi_dreg;
230 	}
231 	return (len);
232 }
233 
234 static int
235 scsiicmd(hs, target, cbuf, clen, buf, len, xferphase)
236 	struct scsi_softc *hs;
237 	int target;
238 	u_char *cbuf;
239 	int clen;
240 	u_char *buf;
241 	int len;
242 	u_char xferphase;
243 {
244 	volatile register struct scsidevice *hd =
245 				(struct scsidevice *)hs->sc_addr;
246 	int i;
247 	u_char phase, ints;
248 	register int wait;
249 
250 	/* select the SCSI bus (it's an error if bus isn't free) */
251 	if (issue_select(hd, target, hs->sc_scsi_addr))
252 		return (0);
253 	if (wait_for_select(hd))
254 		return (0);
255 	/*
256 	 * Wait for a phase change (or error) then let the device
257 	 * sequence us through the various SCSI phases.
258 	 */
259 	phase = CMD_PHASE;
260 	while (1) {
261 		wait = scsi_cmd_wait;
262 		switch (phase) {
263 
264 		case CMD_PHASE:
265 			if (ixfer_start(hd, clen, phase, wait))
266 				if (ixfer_out(hd, clen, cbuf))
267 					goto abort;
268 			phase = xferphase;
269 			break;
270 
271 		case DATA_IN_PHASE:
272 			if (len <= 0)
273 				goto abort;
274 			wait = scsi_data_wait;
275 			if (ixfer_start(hd, len, phase, wait) ||
276 			    !(hd->scsi_ssts & SSTS_DREG_EMPTY))
277 				ixfer_in(hd, len, buf);
278 			phase = STATUS_PHASE;
279 			break;
280 
281 		case DATA_OUT_PHASE:
282 			if (len <= 0)
283 				goto abort;
284 			wait = scsi_data_wait;
285 			if (ixfer_start(hd, len, phase, wait))
286 				if (ixfer_out(hd, len, buf))
287 					goto abort;
288 			phase = STATUS_PHASE;
289 			break;
290 
291 		case STATUS_PHASE:
292 			wait = scsi_data_wait;
293 			if (ixfer_start(hd, sizeof(hs->sc_stat), phase, wait) ||
294 			    !(hd->scsi_ssts & SSTS_DREG_EMPTY))
295 				ixfer_in(hd, sizeof(hs->sc_stat), &hs->sc_stat);
296 			phase = MESG_IN_PHASE;
297 			break;
298 
299 		case MESG_IN_PHASE:
300 			if (ixfer_start(hd, sizeof(hs->sc_msg), phase, wait) ||
301 			    !(hd->scsi_ssts & SSTS_DREG_EMPTY)) {
302 				ixfer_in(hd, sizeof(hs->sc_msg), &hs->sc_msg);
303 				hd->scsi_scmd = SCMD_RST_ACK;
304 			}
305 			phase = BUS_FREE_PHASE;
306 			break;
307 
308 		case BUS_FREE_PHASE:
309 			return (1);
310 
311 		default:
312 			printf("unexpected scsi phase %d\n", phase);
313 			goto abort;
314 		}
315 		/* wait for last command to complete */
316 		while ((ints = hd->scsi_ints) == 0) {
317 			if (--wait < 0)
318 				goto abort;
319 			DELAY(1);
320 		}
321 		hd->scsi_ints = ints;
322 		if (ints & INTS_SRV_REQ)
323 			phase = hd->scsi_psns & PHASE;
324 		else if (ints & INTS_DISCON)
325 			return (1);
326 		else if ((ints & INTS_CMD_DONE) == 0) {
327 			goto abort;
328 		}
329 	}
330 abort:
331 	scsiabort(hs, hd);
332 	return (0);
333 }
334 
335 int
336 scsi_test_unit_rdy(unit)
337 {
338 	int ctlr = scsiunit(unit);
339 	int slave = scsislave(unit);
340 	register struct scsi_softc *hs = &scsi_softc[ctlr];
341 	static struct scsi_cdb6 cdb = { CMD_TEST_UNIT_READY };
342 
343 	if (scsiicmd(hs, slave, &cdb, sizeof(cdb), (u_char *)0, 0,
344 		     STATUS_PHASE) == 0)
345 		return (0);
346 
347 	return (hs->sc_stat == 0);
348 }
349 
350 int
351 scsi_request_sense(unit, buf, len)
352 	int unit;
353 	u_char *buf;
354 	unsigned len;
355 {
356 	int ctlr = scsiunit(unit);
357 	int slave = scsislave(unit);
358 	register struct scsi_softc *hs = &scsi_softc[ctlr];
359 	static struct scsi_cdb6 cdb = { CMD_REQUEST_SENSE };
360 
361 	cdb.len = len;
362 	return (scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_IN_PHASE));
363 }
364 
365 int
366 scsi_read_capacity(unit, buf, len)
367 	int unit;
368 	u_char *buf;
369 	unsigned len;
370 {
371 	int ctlr = scsiunit(unit);
372 	int slave = scsislave(unit);
373 	register struct scsi_softc *hs = &scsi_softc[ctlr];
374 	static struct scsi_cdb10 cdb = { CMD_READ_CAPACITY };
375 
376 	return (scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_IN_PHASE));
377 }
378 
379 int
380 scsi_tt_read(unit, buf, len, blk, nblk)
381 	int unit;
382 	u_char *buf;
383 	u_int len;
384 	daddr_t blk;
385 	u_int nblk;
386 {
387 	int ctlr = scsiunit(unit);
388 	int slave = scsislave(unit);
389 	register struct scsi_softc *hs = &scsi_softc[ctlr];
390 	struct scsi_cdb10 cdb;
391 	int stat;
392 
393 	bzero(&cdb, sizeof(cdb));
394 	cdb.cmd = CMD_READ_EXT;
395 	cdb.lbah = blk >> 24;
396 	cdb.lbahm = blk >> 16;
397 	cdb.lbalm = blk >> 8;
398 	cdb.lbal = blk;
399 	cdb.lenh = nblk >> (8 + DEV_BSHIFT);
400 	cdb.lenl = nblk >> DEV_BSHIFT;
401 	stat = scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_IN_PHASE);
402 	if (stat == 0)
403 		return (1);
404 	return (hs->sc_stat);
405 }
406 
407 int
408 scsi_tt_write(unit, buf, len, blk, nblk)
409 	int unit;
410 	u_char *buf;
411 	u_int len;
412 	daddr_t blk;
413 	u_int nblk;
414 {
415 	int ctlr = scsiunit(unit);
416 	int slave = scsislave(unit);
417 	register struct scsi_softc *hs = &scsi_softc[ctlr];
418 	struct scsi_cdb10 cdb;
419 	int stat;
420 
421 	bzero(&cdb, sizeof(cdb));
422 	cdb.cmd = CMD_WRITE_EXT;
423 	cdb.lbah = blk >> 24;
424 	cdb.lbahm = blk >> 16;
425 	cdb.lbalm = blk >> 8;
426 	cdb.lbal = blk;
427 	cdb.lenh = nblk >> (8 + DEV_BSHIFT);
428 	cdb.lenl = nblk >> DEV_BSHIFT;
429 	stat = scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_OUT_PHASE);
430 	if (stat == 0)
431 		return (1);
432 	return (hs->sc_stat);
433 }
434