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