scsi.c revision 1.3 1 /* $NetBSD: scsi.c,v 1.3 2003/08/01 01:25:45 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) 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
62 #include <hp300/stand/common/device.h>
63 #include <hp300/stand/common/scsireg.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