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