No empty .Rs/.Re
[netbsd-mini2440.git] / sys / arch / hp300 / stand / common / scsi.c
blobf1acc655cd2236ddc3549e459d22a0852a9fd2ce
1 /* $NetBSD: scsi.c,v 1.8 2006/06/25 17:40:14 tsutsui Exp $ */
3 /*
4 * This is reported to fix some odd failures when disklabeling
5 * SCSI disks in SYS_INST.
6 */
7 #define SLOWSCSI
9 /*
10 * Copyright (c) 1990, 1993
11 * The Regents of the University of California. All rights reserved.
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.
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.
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.
41 * from: Utah $Hdr: scsi.c 1.3 90/01/27$
43 * @(#)scsi.c 8.1 (Berkeley) 6/10/93
46 * Copyright (c) 1988 University of Utah.
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.
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.
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.
80 * from: Utah $Hdr: scsi.c 1.3 90/01/27$
82 * @(#)scsi.c 8.1 (Berkeley) 6/10/93
86 * SCSI bus driver for standalone programs.
89 #include <sys/param.h>
90 #include <sys/reboot.h>
92 #include <lib/libsa/stand.h>
94 #define _IOCTL_
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>
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);
110 struct scsi_softc scsi_softc[NSCSI];
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 */
116 void
117 scsiinit(void)
119 struct hp_hw *hw;
120 struct scsi_softc *hs;
121 int i;
122 static int waitset = 0;
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++;
138 * Adjust the wait values
140 if (!waitset) {
141 scsi_cmd_wait *= cpuspeed;
142 scsi_data_wait *= cpuspeed;
143 waitset = 1;
148 scsialive(int unit)
151 if (unit >= NSCSI || scsi_softc[unit].sc_alive == 0)
152 return 0;
153 return 1;
156 static void
157 scsireset(int unit)
159 volatile struct scsidevice *hd;
160 struct scsi_softc *hs;
161 u_int i;
163 hs = &scsi_softc[unit];
164 hd = (void *)hs->sc_addr;
165 hd->scsi_id = 0xFF;
166 DELAY(100);
168 * Disable interrupts then reset the FUJI chip.
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;
182 * Configure the FUJI chip with its SCSI address, all
183 * interrupts enabled & appropriate parity.
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;
200 void
201 scsiabort(struct scsi_softc *hs, volatile struct scsidevice *hd)
204 printf("scsi%d error: scsiabort\n", hs - scsi_softc);
206 scsireset(hs - scsi_softc);
207 DELAY(1000000);
210 static int
211 issue_select(volatile struct scsidevice *hd, uint8_t target, uint8_t our_addr)
214 if (hd->scsi_ssts & (SSTS_INITIATOR|SSTS_TARGET|SSTS_BUSY))
215 return 1;
217 if (hd->scsi_ints & INTS_DISCON)
218 hd->scsi_ints = INTS_DISCON;
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;
227 hd->scsi_scmd = SCMD_SELECT;
228 return 0;
231 static int
232 wait_for_select(volatile struct scsidevice *hd)
234 int wait;
235 uint8_t ints;
237 wait = scsi_data_wait;
238 while ((ints = hd->scsi_ints) == 0) {
239 if (--wait < 0)
240 return 1;
241 DELAY(1);
243 hd->scsi_ints = ints;
244 return !(hd->scsi_ssts & SSTS_INITIATOR);
247 static int
248 ixfer_start(volatile struct scsidevice *hd, int len, uint8_t phase, int wait)
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;
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);
264 return 1;
267 static int
268 ixfer_out(volatile struct scsidevice *hd, int len, uint8_t *buf)
270 int wait = scsi_data_wait;
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);
278 hd->scsi_dreg = *buf++;
280 return 0;
283 static int
284 ixfer_in(volatile struct scsidevice *hd, int len, uint8_t *buf)
286 int wait = scsi_data_wait;
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;
295 return len;
297 DELAY(1);
299 *buf++ = hd->scsi_dreg;
301 return len;
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)
308 volatile struct scsidevice *hd = (void *)hs->sc_addr;
309 uint8_t phase, ints;
310 int wait;
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;
318 * Wait for a phase change (or error) then let the device
319 * sequence us through the various SCSI phases.
321 hs->sc_stat = -1;
322 phase = CMD_PHASE;
323 while (1) {
324 wait = scsi_cmd_wait;
325 switch (phase) {
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;
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;
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;
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;
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;
370 phase = BUS_FREE_PHASE;
371 break;
373 case BUS_FREE_PHASE:
374 goto out;
376 default:
377 printf("scsi%d: unexpected scsi phase %d\n",
378 hs - scsi_softc, phase);
379 goto abort;
381 #ifdef SLOWSCSI
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.
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);
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;
404 abort:
405 scsiabort(hs, hd);
406 out:
407 return hs->sc_stat;
411 scsi_test_unit_rdy(int ctlr, int slave)
413 struct scsi_softc *hs = &scsi_softc[ctlr];
414 static struct scsi_cdb6 cdb = { CMD_TEST_UNIT_READY };
416 return scsiicmd(hs, slave, (uint8_t *)&cdb, sizeof(cdb), NULL, 0,
417 STATUS_PHASE);
421 scsi_request_sense(int ctlr, int slave, uint8_t *buf, unsigned int len)
423 struct scsi_softc *hs = &scsi_softc[ctlr];
424 static struct scsi_cdb6 cdb = { CMD_REQUEST_SENSE };
426 cdb.len = len;
427 return scsiicmd(hs, slave, (uint8_t *)&cdb, sizeof(cdb), buf, len,
428 DATA_IN_PHASE);
432 scsi_read_capacity(int ctlr, int slave, uint8_t *buf, unsigned int len)
434 struct scsi_softc *hs = &scsi_softc[ctlr];
435 static struct scsi_cdb10 cdb = { CMD_READ_CAPACITY };
437 return scsiicmd(hs, slave, (uint8_t *)&cdb, sizeof(cdb), buf, len,
438 DATA_IN_PHASE);
442 scsi_tt_read(int ctlr, int slave, uint8_t *buf, u_int len, daddr_t blk,
443 u_int nblk)
445 struct scsi_softc *hs = &scsi_softc[ctlr];
446 struct scsi_cdb10 cdb;
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);
461 scsi_tt_write(int ctlr, int slave, uint8_t *buf, u_int len, daddr_t blk,
462 u_int nblk)
464 struct scsi_softc *hs = &scsi_softc[ctlr];
465 struct scsi_cdb10 cdb;
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);