xref: /netbsd/sys/arch/hp300/stand/common/scsi.c (revision 6550d01e)
1 /*	$NetBSD: scsi.c,v 1.9 2007/03/04 05:59:50 christos 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 *, uint8_t, uint8_t);
103 static int wait_for_select(volatile struct scsidevice *hd);
104 static int ixfer_start(volatile struct scsidevice *, int, uint8_t, int);
105 static int ixfer_out(volatile struct scsidevice *, int, uint8_t *);
106 static int ixfer_in(volatile struct scsidevice *hd, int, uint8_t *);
107 static int scsiicmd(struct scsi_softc *, int, uint8_t *, int, uint8_t *, int,
108     uint8_t);
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(void)
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 = (void *) 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(int unit)
149 {
150 
151 	if (unit >= NSCSI || scsi_softc[unit].sc_alive == 0)
152 		return 0;
153 	return 1;
154 }
155 
156 static void
157 scsireset(int unit)
158 {
159 	volatile struct scsidevice *hd;
160 	struct scsi_softc *hs;
161 	u_int i;
162 
163 	hs = &scsi_softc[unit];
164 	hd = (void *)hs->sc_addr;
165 	hd->scsi_id = 0xFF;
166 	DELAY(100);
167 	/*
168 	 * Disable interrupts then reset the FUJI chip.
169 	 */
170 	hd->scsi_csr  = 0;
171 	hd->scsi_sctl = SCTL_DISABLE | SCTL_CTRLRST;
172 	hd->scsi_scmd = 0;
173 	hd->scsi_tmod = 0;
174 	hd->scsi_pctl = 0;
175 	hd->scsi_temp = 0;
176 	hd->scsi_tch  = 0;
177 	hd->scsi_tcm  = 0;
178 	hd->scsi_tcl  = 0;
179 	hd->scsi_ints = 0;
180 
181 	/*
182 	 * Configure the FUJI chip with its SCSI address, all
183 	 * interrupts enabled & appropriate parity.
184 	 */
185 	i = (~hd->scsi_hconf) & 0x7;
186 	hs->sc_scsi_addr = 1 << i;
187 	hd->scsi_bdid = i;
188 	if (hd->scsi_hconf & HCONF_PARITY)
189 		hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB |
190 				SCTL_SEL_ENAB | SCTL_RESEL_ENAB |
191 				SCTL_INTR_ENAB | SCTL_PARITY_ENAB;
192 	else
193 		hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB |
194 				SCTL_SEL_ENAB | SCTL_RESEL_ENAB |
195 				SCTL_INTR_ENAB;
196 	hd->scsi_sctl &=~ SCTL_DISABLE;
197 }
198 
199 
200 void
201 scsiabort(struct scsi_softc *hs, volatile struct scsidevice *hd)
202 {
203 
204 	printf("scsi%d error: scsiabort\n", hs - scsi_softc);
205 
206 	scsireset(hs - scsi_softc);
207 	DELAY(1000000);
208 }
209 
210 static int
211 issue_select(volatile struct scsidevice *hd, uint8_t target, uint8_t our_addr)
212 {
213 
214 	if (hd->scsi_ssts & (SSTS_INITIATOR|SSTS_TARGET|SSTS_BUSY))
215 		return 1;
216 
217 	if (hd->scsi_ints & INTS_DISCON)
218 		hd->scsi_ints = INTS_DISCON;
219 
220 	hd->scsi_pctl = 0;
221 	hd->scsi_temp = (1 << target) | our_addr;
222 	/* select timeout is hardcoded to 2ms */
223 	hd->scsi_tch = 0;
224 	hd->scsi_tcm = 32;
225 	hd->scsi_tcl = 4;
226 
227 	hd->scsi_scmd = SCMD_SELECT;
228 	return 0;
229 }
230 
231 static int
232 wait_for_select(volatile struct scsidevice *hd)
233 {
234 	int wait;
235 	uint8_t ints;
236 
237 	wait = scsi_data_wait;
238 	while ((ints = hd->scsi_ints) == 0) {
239 		if (--wait < 0)
240 			return 1;
241 		DELAY(1);
242 	}
243 	hd->scsi_ints = ints;
244 	return !(hd->scsi_ssts & SSTS_INITIATOR);
245 }
246 
247 static int
248 ixfer_start(volatile struct scsidevice *hd, int len, uint8_t phase, int wait)
249 {
250 
251 	hd->scsi_tch = len >> 16;
252 	hd->scsi_tcm = len >> 8;
253 	hd->scsi_tcl = len;
254 	hd->scsi_pctl = phase;
255 	hd->scsi_tmod = 0; /*XXX*/
256 	hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR;
257 
258 	/* wait for xfer to start or svc_req interrupt */
259 	while ((hd->scsi_ssts & SSTS_BUSY) == 0) {
260 		if (hd->scsi_ints || --wait < 0)
261 			return 0;
262 		DELAY(1);
263 	}
264 	return 1;
265 }
266 
267 static int
268 ixfer_out(volatile struct scsidevice *hd, int len, uint8_t *buf)
269 {
270 	int wait = scsi_data_wait;
271 
272 	for (; len > 0; --len) {
273 		while (hd->scsi_ssts & SSTS_DREG_FULL) {
274 			if (hd->scsi_ints || --wait < 0)
275 				return len;
276 			DELAY(1);
277 		}
278 		hd->scsi_dreg = *buf++;
279 	}
280 	return 0;
281 }
282 
283 static int
284 ixfer_in(volatile struct scsidevice *hd, int len, uint8_t *buf)
285 {
286 	int wait = scsi_data_wait;
287 
288 	for (; len > 0; --len) {
289 		while (hd->scsi_ssts & SSTS_DREG_EMPTY) {
290 			if (hd->scsi_ints || --wait < 0) {
291 				while (! (hd->scsi_ssts & SSTS_DREG_EMPTY)) {
292 					*buf++ = hd->scsi_dreg;
293 					--len;
294 				}
295 				return len;
296 			}
297 			DELAY(1);
298 		}
299 		*buf++ = hd->scsi_dreg;
300 	}
301 	return len;
302 }
303 
304 static int
305 scsiicmd(struct scsi_softc *hs, int target, uint8_t *cbuf, int clen,
306     uint8_t *buf, int len, uint8_t xferphase)
307 {
308 	volatile struct scsidevice *hd = (void *)hs->sc_addr;
309 	uint8_t phase, ints;
310 	int wait;
311 
312 	/* select the SCSI bus (it's an error if bus isn't free) */
313 	if (issue_select(hd, target, hs->sc_scsi_addr))
314 		return -2;
315 	if (wait_for_select(hd))
316 		return -2;
317 	/*
318 	 * Wait for a phase change (or error) then let the device
319 	 * sequence us through the various SCSI phases.
320 	 */
321 	hs->sc_stat = -1;
322 	phase = CMD_PHASE;
323 	while (1) {
324 		wait = scsi_cmd_wait;
325 		switch (phase) {
326 
327 		case CMD_PHASE:
328 			if (ixfer_start(hd, clen, phase, wait))
329 				if (ixfer_out(hd, clen, cbuf))
330 					goto abort;
331 			phase = xferphase;
332 			break;
333 
334 		case DATA_IN_PHASE:
335 			if (len <= 0)
336 				goto abort;
337 			wait = scsi_data_wait;
338 			if (ixfer_start(hd, len, phase, wait) ||
339 			    !(hd->scsi_ssts & SSTS_DREG_EMPTY))
340 				ixfer_in(hd, len, buf);
341 			phase = STATUS_PHASE;
342 			break;
343 
344 		case DATA_OUT_PHASE:
345 			if (len <= 0)
346 				goto abort;
347 			wait = scsi_data_wait;
348 			if (ixfer_start(hd, len, phase, wait))
349 				if (ixfer_out(hd, len, buf))
350 					goto abort;
351 			phase = STATUS_PHASE;
352 			break;
353 
354 		case STATUS_PHASE:
355 			wait = scsi_data_wait;
356 			if (ixfer_start(hd, sizeof(hs->sc_stat), phase, wait) ||
357 			    !(hd->scsi_ssts & SSTS_DREG_EMPTY))
358 				ixfer_in(hd, sizeof(hs->sc_stat),
359 				    (uint8_t *)&hs->sc_stat);
360 			phase = MESG_IN_PHASE;
361 			break;
362 
363 		case MESG_IN_PHASE:
364 			if (ixfer_start(hd, sizeof(hs->sc_msg), phase, wait) ||
365 			    !(hd->scsi_ssts & SSTS_DREG_EMPTY)) {
366 				ixfer_in(hd, sizeof(hs->sc_msg),
367 				    (uint8_t *)&hs->sc_msg);
368 				hd->scsi_scmd = SCMD_RST_ACK;
369 			}
370 			phase = BUS_FREE_PHASE;
371 			break;
372 
373 		case BUS_FREE_PHASE:
374 			goto out;
375 
376 		default:
377 			printf("scsi%d: unexpected scsi phase %d\n",
378 			       hs - scsi_softc, phase);
379 			goto abort;
380 		}
381 #ifdef SLOWSCSI
382 		/*
383 		 * XXX we have weird transient problems with booting from
384 		 * slow scsi disks on fast machines.  I have never been
385 		 * able to pin the problem down, but a large delay here
386 		 * seems to always work.
387 		 */
388 		DELAY(1000);
389 #endif
390 		/* wait for last command to complete */
391 		while ((ints = hd->scsi_ints) == 0) {
392 			if (--wait < 0)
393 				goto abort;
394 			DELAY(1);
395 		}
396 		hd->scsi_ints = ints;
397 		if (ints & INTS_SRV_REQ)
398 			phase = hd->scsi_psns & PHASE;
399 		else if (ints & INTS_DISCON)
400 			goto out;
401 		else if ((ints & INTS_CMD_DONE) == 0)
402 			goto abort;
403 	}
404 abort:
405 	scsiabort(hs, hd);
406 out:
407 	return hs->sc_stat;
408 }
409 
410 int
411 scsi_test_unit_rdy(int ctlr, int slave)
412 {
413 	struct scsi_softc *hs = &scsi_softc[ctlr];
414 	static struct scsi_cdb6 cdb = { CMD_TEST_UNIT_READY };
415 
416 	return scsiicmd(hs, slave, (uint8_t *)&cdb, sizeof(cdb), NULL, 0,
417 	    STATUS_PHASE);
418 }
419 
420 int
421 scsi_request_sense(int ctlr, int slave, uint8_t *buf, unsigned int len)
422 {
423 	struct scsi_softc *hs = &scsi_softc[ctlr];
424 	static struct scsi_cdb6 cdb = { CMD_REQUEST_SENSE };
425 
426 	cdb.len = len;
427 	return scsiicmd(hs, slave, (uint8_t *)&cdb, sizeof(cdb), buf, len,
428 	    DATA_IN_PHASE);
429 }
430 
431 int
432 scsi_read_capacity(int ctlr, int slave, uint8_t *buf, unsigned int len)
433 {
434 	struct scsi_softc *hs = &scsi_softc[ctlr];
435 	static struct scsi_cdb10 cdb = { CMD_READ_CAPACITY };
436 
437 	return scsiicmd(hs, slave, (uint8_t *)&cdb, sizeof(cdb), buf, len,
438 	    DATA_IN_PHASE);
439 }
440 
441 int
442 scsi_tt_read(int ctlr, int slave, uint8_t *buf, u_int len, daddr_t blk,
443     u_int nblk)
444 {
445 	struct scsi_softc *hs = &scsi_softc[ctlr];
446 	struct scsi_cdb10 cdb;
447 
448 	memset(&cdb, 0, sizeof(cdb));
449 	cdb.cmd = CMD_READ_EXT;
450 	cdb.lbah = blk >> 24;
451 	cdb.lbahm = blk >> 16;
452 	cdb.lbalm = blk >> 8;
453 	cdb.lbal = blk;
454 	cdb.lenh = nblk >> (8 + DEV_BSHIFT);
455 	cdb.lenl = nblk >> DEV_BSHIFT;
456 	return scsiicmd(hs, slave, (uint8_t *)&cdb, sizeof(cdb), buf, len,
457 	    DATA_IN_PHASE);
458 }
459 
460 int
461 scsi_tt_write(int ctlr, int slave, uint8_t *buf, u_int len, daddr_t blk,
462     u_int nblk)
463 {
464 	struct scsi_softc *hs = &scsi_softc[ctlr];
465 	struct scsi_cdb10 cdb;
466 
467 	memset(&cdb, 0, sizeof(cdb));
468 	cdb.cmd = CMD_WRITE_EXT;
469 	cdb.lbah = blk >> 24;
470 	cdb.lbahm = blk >> 16;
471 	cdb.lbalm = blk >> 8;
472 	cdb.lbal = blk;
473 	cdb.lenh = nblk >> (8 + DEV_BSHIFT);
474 	cdb.lenl = nblk >> DEV_BSHIFT;
475 	return scsiicmd(hs, slave, (uint8_t *)&cdb, sizeof(cdb), buf, len,
476 	    DATA_OUT_PHASE);
477 }
478