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