1 /* $NetBSD: scsi.c,v 1.13 2024/05/09 15:11:11 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. Neither the name of the University nor the names of its contributors
27 * may be used to endorse or promote products derived from this software
28 * without specific prior written permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * SUCH DAMAGE.
41 *
42 * from: Utah $Hdr: scsi.c 1.3 90/01/27$
43 *
44 * @(#)scsi.c 8.1 (Berkeley) 6/10/93
45 */
46
47 /*
48 * SCSI bus driver for standalone programs.
49 */
50
51 #include <sys/param.h>
52 #include <sys/reboot.h>
53
54 #include <lib/libsa/stand.h>
55
56 #define _IOCTL_
57
58 #include <hp300/stand/common/device.h>
59 #include <hp300/stand/common/scsireg.h>
60 #include <hp300/stand/common/scsivar.h>
61 #include <hp300/stand/common/samachdep.h>
62
63 static void scsireset(int);
64 static int issue_select(volatile struct scsidevice *, uint8_t, uint8_t);
65 static int wait_for_select(volatile struct scsidevice *hd);
66 static int ixfer_start(volatile struct scsidevice *, int, uint8_t, int);
67 static int ixfer_out(volatile struct scsidevice *, int, uint8_t *);
68 static int ixfer_in(volatile struct scsidevice *hd, int, uint8_t *);
69 static int scsiicmd(struct scsi_softc *, int, uint8_t *, int, uint8_t *, int,
70 uint8_t);
71
72 struct scsi_softc scsi_softc[NSCSI];
73
74
75 int scsi_cmd_wait = 50000; /* use the "real" driver init_wait value */
76 int scsi_data_wait = 50000; /* use the "real" driver init_wait value */
77
78 void
scsiinit(void)79 scsiinit(void)
80 {
81 struct hp_hw *hw;
82 struct scsi_softc *hs;
83 int i;
84 static int waitset = 0;
85
86 i = 0;
87 for (hw = sc_table; i < NSCSI && hw < &sc_table[MAXCTLRS]; hw++) {
88 if (!HW_ISSCSI(hw))
89 continue;
90 hs = &scsi_softc[i];
91 hs->sc_addr = hw->hw_kva;
92 scsireset(i);
93 if (howto & RB_ASKNAME)
94 printf("scsi%d at sc%d\n", i, hw->hw_sc);
95 hw->hw_pa = (void *) i; /* XXX for autoconfig */
96 hs->sc_alive = 1;
97 i++;
98 }
99 /*
100 * Adjust the wait values
101 */
102 if (!waitset) {
103 scsi_cmd_wait *= cpuspeed;
104 scsi_data_wait *= cpuspeed;
105 waitset = 1;
106 }
107 }
108
109 int
scsialive(int unit)110 scsialive(int unit)
111 {
112
113 if (unit >= NSCSI || scsi_softc[unit].sc_alive == 0)
114 return 0;
115 return 1;
116 }
117
118 static void
scsireset(int unit)119 scsireset(int unit)
120 {
121 volatile struct scsidevice *hd;
122 struct scsi_softc *hs;
123 u_int i;
124
125 hs = &scsi_softc[unit];
126 hd = (void *)hs->sc_addr;
127 hd->scsi_id = 0xFF;
128 DELAY(100);
129 /*
130 * Disable interrupts then reset the FUJI chip.
131 */
132 hd->scsi_csr = 0;
133 hd->scsi_sctl = SCTL_DISABLE | SCTL_CTRLRST;
134 hd->scsi_scmd = 0;
135 hd->scsi_tmod = 0;
136 hd->scsi_pctl = 0;
137 hd->scsi_temp = 0;
138 hd->scsi_tch = 0;
139 hd->scsi_tcm = 0;
140 hd->scsi_tcl = 0;
141 hd->scsi_ints = 0;
142
143 /*
144 * Configure the FUJI chip with its SCSI address, all
145 * interrupts enabled & appropriate parity.
146 */
147 i = (~hd->scsi_hconf) & 0x7;
148 hs->sc_scsi_addr = 1 << i;
149 hd->scsi_bdid = i;
150 if (hd->scsi_hconf & HCONF_PARITY)
151 hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB |
152 SCTL_SEL_ENAB | SCTL_RESEL_ENAB |
153 SCTL_INTR_ENAB | SCTL_PARITY_ENAB;
154 else
155 hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB |
156 SCTL_SEL_ENAB | SCTL_RESEL_ENAB |
157 SCTL_INTR_ENAB;
158 hd->scsi_sctl &=~ SCTL_DISABLE;
159 }
160
161
162 void
scsiabort(struct scsi_softc * hs,volatile struct scsidevice * hd)163 scsiabort(struct scsi_softc *hs, volatile struct scsidevice *hd)
164 {
165
166 printf("scsi%d error: scsiabort\n", hs - scsi_softc);
167
168 scsireset(hs - scsi_softc);
169 DELAY(1000000);
170 }
171
172 static int
issue_select(volatile struct scsidevice * hd,uint8_t target,uint8_t our_addr)173 issue_select(volatile struct scsidevice *hd, uint8_t target, uint8_t our_addr)
174 {
175
176 if (hd->scsi_ssts & (SSTS_INITIATOR|SSTS_TARGET|SSTS_BUSY))
177 return 1;
178
179 if (hd->scsi_ints & INTS_DISCON)
180 hd->scsi_ints = INTS_DISCON;
181
182 hd->scsi_pctl = 0;
183 hd->scsi_temp = (1 << target) | our_addr;
184 /* select timeout is hardcoded to 250ms */
185 hd->scsi_tch = 2;
186 hd->scsi_tcm = 113;
187 hd->scsi_tcl = 3;
188
189 hd->scsi_scmd = SCMD_SELECT;
190 return 0;
191 }
192
193 static int
wait_for_select(volatile struct scsidevice * hd)194 wait_for_select(volatile struct scsidevice *hd)
195 {
196 int wait;
197 uint8_t ints;
198
199 wait = scsi_data_wait;
200 while ((ints = hd->scsi_ints) == 0) {
201 if (--wait < 0)
202 return 1;
203 DELAY(1);
204 }
205 hd->scsi_ints = ints;
206 return !(hd->scsi_ssts & SSTS_INITIATOR);
207 }
208
209 static int
ixfer_start(volatile struct scsidevice * hd,int len,uint8_t phase,int wait)210 ixfer_start(volatile struct scsidevice *hd, int len, uint8_t phase, int wait)
211 {
212
213 hd->scsi_tch = len >> 16;
214 hd->scsi_tcm = len >> 8;
215 hd->scsi_tcl = len;
216 hd->scsi_pctl = phase;
217 hd->scsi_tmod = 0; /*XXX*/
218 hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR;
219
220 /* wait for xfer to start or svc_req interrupt */
221 while ((hd->scsi_ssts & SSTS_BUSY) == 0) {
222 if (hd->scsi_ints || --wait < 0)
223 return 0;
224 DELAY(1);
225 }
226 return 1;
227 }
228
229 static int
ixfer_out(volatile struct scsidevice * hd,int len,uint8_t * buf)230 ixfer_out(volatile struct scsidevice *hd, int len, uint8_t *buf)
231 {
232 int wait = scsi_data_wait;
233
234 for (; len > 0; --len) {
235 while (hd->scsi_ssts & SSTS_DREG_FULL) {
236 if (hd->scsi_ints || --wait < 0)
237 return len;
238 DELAY(1);
239 }
240 hd->scsi_dreg = *buf++;
241 }
242 return 0;
243 }
244
245 static int
ixfer_in(volatile struct scsidevice * hd,int len,uint8_t * buf)246 ixfer_in(volatile struct scsidevice *hd, int len, uint8_t *buf)
247 {
248 int wait = scsi_data_wait;
249
250 for (; len > 0; --len) {
251 while (hd->scsi_ssts & SSTS_DREG_EMPTY) {
252 if (hd->scsi_ints || --wait < 0) {
253 while (! (hd->scsi_ssts & SSTS_DREG_EMPTY)) {
254 *buf++ = hd->scsi_dreg;
255 --len;
256 }
257 return len;
258 }
259 DELAY(1);
260 }
261 *buf++ = hd->scsi_dreg;
262 }
263 return len;
264 }
265
266 static int
scsiicmd(struct scsi_softc * hs,int target,uint8_t * cbuf,int clen,uint8_t * buf,int len,uint8_t xferphase)267 scsiicmd(struct scsi_softc *hs, int target, uint8_t *cbuf, int clen,
268 uint8_t *buf, int len, uint8_t xferphase)
269 {
270 volatile struct scsidevice *hd = (void *)hs->sc_addr;
271 uint8_t phase, ints;
272 int wait;
273
274 /* select the SCSI bus (it's an error if bus isn't free) */
275 if (issue_select(hd, target, hs->sc_scsi_addr))
276 return -2;
277 if (wait_for_select(hd))
278 return -2;
279 /*
280 * Wait for a phase change (or error) then let the device
281 * sequence us through the various SCSI phases.
282 */
283 hs->sc_stat = -1;
284 phase = CMD_PHASE;
285 while (1) {
286 wait = scsi_cmd_wait;
287 switch (phase) {
288
289 case CMD_PHASE:
290 if (ixfer_start(hd, clen, phase, wait))
291 if (ixfer_out(hd, clen, cbuf))
292 goto abort;
293 phase = xferphase;
294 break;
295
296 case DATA_IN_PHASE:
297 if (len <= 0)
298 goto abort;
299 wait = scsi_data_wait;
300 if (ixfer_start(hd, len, phase, wait) ||
301 !(hd->scsi_ssts & SSTS_DREG_EMPTY))
302 ixfer_in(hd, len, buf);
303 phase = STATUS_PHASE;
304 break;
305
306 case DATA_OUT_PHASE:
307 if (len <= 0)
308 goto abort;
309 wait = scsi_data_wait;
310 if (ixfer_start(hd, len, phase, wait))
311 if (ixfer_out(hd, len, buf))
312 goto abort;
313 phase = STATUS_PHASE;
314 break;
315
316 case STATUS_PHASE:
317 wait = scsi_data_wait;
318 if (ixfer_start(hd, sizeof(hs->sc_stat), phase, wait) ||
319 !(hd->scsi_ssts & SSTS_DREG_EMPTY))
320 ixfer_in(hd, sizeof(hs->sc_stat),
321 (uint8_t *)&hs->sc_stat);
322 phase = MESG_IN_PHASE;
323 break;
324
325 case MESG_IN_PHASE:
326 if (ixfer_start(hd, sizeof(hs->sc_msg), phase, wait) ||
327 !(hd->scsi_ssts & SSTS_DREG_EMPTY)) {
328 ixfer_in(hd, sizeof(hs->sc_msg),
329 (uint8_t *)&hs->sc_msg);
330 hd->scsi_scmd = SCMD_RST_ACK;
331 }
332 phase = BUS_FREE_PHASE;
333 break;
334
335 case BUS_FREE_PHASE:
336 goto out;
337
338 default:
339 printf("scsi%d: unexpected scsi phase %d\n",
340 hs - scsi_softc, phase);
341 goto abort;
342 }
343 #ifdef SLOWSCSI
344 /*
345 * XXX we have weird transient problems with booting from
346 * slow scsi disks on fast machines. I have never been
347 * able to pin the problem down, but a large delay here
348 * seems to always work.
349 */
350 DELAY(1000);
351 #endif
352 /* wait for last command to complete */
353 while ((ints = hd->scsi_ints) == 0) {
354 if (--wait < 0)
355 goto abort;
356 DELAY(1);
357 }
358 hd->scsi_ints = ints;
359 if (ints & INTS_SRV_REQ)
360 phase = hd->scsi_psns & PHASE;
361 else if (ints & INTS_DISCON)
362 goto out;
363 else if ((ints & INTS_CMD_DONE) == 0)
364 goto abort;
365 }
366 abort:
367 scsiabort(hs, hd);
368 out:
369 return hs->sc_stat;
370 }
371
372 int
scsi_test_unit_rdy(int ctlr,int slave)373 scsi_test_unit_rdy(int ctlr, int slave)
374 {
375 struct scsi_softc *hs = &scsi_softc[ctlr];
376 static struct scsi_cdb6 cdb = { CMD_TEST_UNIT_READY };
377
378 return scsiicmd(hs, slave, (uint8_t *)&cdb, sizeof(cdb), NULL, 0,
379 STATUS_PHASE);
380 }
381
382 int
scsi_request_sense(int ctlr,int slave,uint8_t * buf,unsigned int len)383 scsi_request_sense(int ctlr, int slave, uint8_t *buf, unsigned int len)
384 {
385 struct scsi_softc *hs = &scsi_softc[ctlr];
386 static struct scsi_cdb6 cdb = { CMD_REQUEST_SENSE };
387
388 cdb.len = len;
389 return scsiicmd(hs, slave, (uint8_t *)&cdb, sizeof(cdb), buf, len,
390 DATA_IN_PHASE);
391 }
392
393 int
scsi_read_capacity(int ctlr,int slave,uint8_t * buf,unsigned int len)394 scsi_read_capacity(int ctlr, int slave, uint8_t *buf, unsigned int len)
395 {
396 struct scsi_softc *hs = &scsi_softc[ctlr];
397 static struct scsi_cdb10 cdb = { CMD_READ_CAPACITY };
398
399 return scsiicmd(hs, slave, (uint8_t *)&cdb, sizeof(cdb), buf, len,
400 DATA_IN_PHASE);
401 }
402
403 #ifdef SUPPORT_CD
404 int
scsi_inquiry(int ctlr,int slave,uint8_t * buf,unsigned int len)405 scsi_inquiry(int ctlr, int slave, uint8_t *buf, unsigned int len)
406 {
407 struct scsi_softc *hs = &scsi_softc[ctlr];
408 static struct scsi_cdb6 cdb = { CMD_INQUIRY };
409
410 cdb.len = len;
411 return scsiicmd(hs, slave, (uint8_t *)&cdb, sizeof(cdb), buf, len,
412 DATA_IN_PHASE);
413 }
414 #endif
415
416 int
scsi_tt_read(int ctlr,int slave,uint8_t * buf,u_int len,daddr_t blk,u_int nblk)417 scsi_tt_read(int ctlr, int slave, uint8_t *buf, u_int len, daddr_t blk,
418 u_int nblk)
419 {
420 struct scsi_softc *hs = &scsi_softc[ctlr];
421 struct scsi_cdb10 cdb;
422
423 memset(&cdb, 0, sizeof(cdb));
424 cdb.cmd = CMD_READ_EXT;
425 cdb.lbah = blk >> 24;
426 cdb.lbahm = blk >> 16;
427 cdb.lbalm = blk >> 8;
428 cdb.lbal = blk;
429 cdb.lenh = nblk >> (8 + DEV_BSHIFT);
430 cdb.lenl = nblk >> DEV_BSHIFT;
431 return scsiicmd(hs, slave, (uint8_t *)&cdb, sizeof(cdb), buf, len,
432 DATA_IN_PHASE);
433 }
434
435 int
scsi_tt_write(int ctlr,int slave,uint8_t * buf,u_int len,daddr_t blk,u_int nblk)436 scsi_tt_write(int ctlr, int slave, uint8_t *buf, u_int len, daddr_t blk,
437 u_int nblk)
438 {
439 struct scsi_softc *hs = &scsi_softc[ctlr];
440 struct scsi_cdb10 cdb;
441
442 memset(&cdb, 0, sizeof(cdb));
443 cdb.cmd = CMD_WRITE_EXT;
444 cdb.lbah = blk >> 24;
445 cdb.lbahm = blk >> 16;
446 cdb.lbalm = blk >> 8;
447 cdb.lbal = blk;
448 cdb.lenh = nblk >> (8 + DEV_BSHIFT);
449 cdb.lenl = nblk >> DEV_BSHIFT;
450 return scsiicmd(hs, slave, (uint8_t *)&cdb, sizeof(cdb), buf, len,
451 DATA_OUT_PHASE);
452 }
453