1 /* $NetBSD: scsi.c,v 1.8 2006/06/25 17:40:14 tsutsui Exp $ */
4 * This is reported to fix some odd failures when disklabeling
5 * SCSI disks in SYS_INST.
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
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
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
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
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>
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,
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 */
120 struct scsi_softc
*hs
;
122 static int waitset
= 0;
125 for (hw
= sc_table
; i
< NSCSI
&& hw
< &sc_table
[MAXCTLRS
]; hw
++) {
129 hs
->sc_addr
= hw
->hw_kva
;
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 */
138 * Adjust the wait values
141 scsi_cmd_wait
*= cpuspeed
;
142 scsi_data_wait
*= cpuspeed
;
151 if (unit
>= NSCSI
|| scsi_softc
[unit
].sc_alive
== 0)
159 volatile struct scsidevice
*hd
;
160 struct scsi_softc
*hs
;
163 hs
= &scsi_softc
[unit
];
164 hd
= (void *)hs
->sc_addr
;
168 * Disable interrupts then reset the FUJI chip.
171 hd
->scsi_sctl
= SCTL_DISABLE
| SCTL_CTRLRST
;
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
;
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
;
193 hd
->scsi_sctl
= SCTL_DISABLE
| SCTL_ABRT_ENAB
|
194 SCTL_SEL_ENAB
| SCTL_RESEL_ENAB
|
196 hd
->scsi_sctl
&=~ SCTL_DISABLE
;
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
);
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
))
217 if (hd
->scsi_ints
& INTS_DISCON
)
218 hd
->scsi_ints
= INTS_DISCON
;
221 hd
->scsi_temp
= (1 << target
) | our_addr
;
222 /* select timeout is hardcoded to 2ms */
227 hd
->scsi_scmd
= SCMD_SELECT
;
232 wait_for_select(volatile struct scsidevice
*hd
)
237 wait
= scsi_data_wait
;
238 while ((ints
= hd
->scsi_ints
) == 0) {
243 hd
->scsi_ints
= ints
;
244 return !(hd
->scsi_ssts
& SSTS_INITIATOR
);
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;
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)
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)
278 hd
->scsi_dreg
= *buf
++;
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
;
299 *buf
++ = hd
->scsi_dreg
;
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
;
312 /* select the SCSI bus (it's an error if bus isn't free) */
313 if (issue_select(hd
, target
, hs
->sc_scsi_addr
))
315 if (wait_for_select(hd
))
318 * Wait for a phase change (or error) then let the device
319 * sequence us through the various SCSI phases.
324 wait
= scsi_cmd_wait
;
328 if (ixfer_start(hd
, clen
, phase
, wait
))
329 if (ixfer_out(hd
, clen
, cbuf
))
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
;
347 wait
= scsi_data_wait
;
348 if (ixfer_start(hd
, len
, phase
, wait
))
349 if (ixfer_out(hd
, len
, buf
))
351 phase
= 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
;
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
;
377 printf("scsi%d: unexpected scsi phase %d\n",
378 hs
- scsi_softc
, phase
);
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.
390 /* wait for last command to complete */
391 while ((ints
= hd
->scsi_ints
) == 0) {
396 hd
->scsi_ints
= ints
;
397 if (ints
& INTS_SRV_REQ
)
398 phase
= hd
->scsi_psns
& PHASE
;
399 else if (ints
& INTS_DISCON
)
401 else if ((ints
& INTS_CMD_DONE
) == 0)
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,
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
};
427 return scsiicmd(hs
, slave
, (uint8_t *)&cdb
, sizeof(cdb
), buf
, len
,
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
,
442 scsi_tt_read(int ctlr
, int slave
, uint8_t *buf
, u_int len
, daddr_t blk
,
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;
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
,
461 scsi_tt_write(int ctlr
, int slave
, uint8_t *buf
, u_int len
, daddr_t blk
,
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;
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
,