scsi.c revision 1.5 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