1 /*
2 * Copyright (c) 1988 University of Utah.
3 * Copyright (c) 1990, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Van Jacobson of Lawrence Berkeley Laboratory and the Systems
8 * Programming Group of the University of Utah Computer Science Department.
9 *
10 * %sccs.include.redist.c%
11 *
12 * from: Utah $Hdr: scsi.c 1.3 90/01/27$
13 *
14 * @(#)scsi.c 8.1 (Berkeley) 06/10/93
15 */
16
17 /*
18 * SCSI bus driver for standalone programs.
19 */
20
21 #include <sys/param.h>
22 #include <sys/reboot.h>
23 #include <hp/dev/device.h>
24 #include <hp300/dev/scsireg.h>
25 #include <hp300/stand/scsivar.h>
26
27 #include <stand.att/saio.h>
28 #include <hp300/stand/samachdep.h>
29
30 struct scsi_softc scsi_softc[NSCSI];
31
32 void scsireset();
33 int scsi_cmd_wait = 50000; /* use the "real" driver init_wait value */
34 int scsi_data_wait = 50000; /* use the "real" driver init_wait value */
35
scsiinit()36 scsiinit()
37 {
38 extern struct hp_hw sc_table[];
39 register struct hp_hw *hw;
40 register struct scsi_softc *hs;
41 register int i, addr;
42 static int waitset = 0;
43
44 i = 0;
45 for (hw = sc_table; i < NSCSI && hw < &sc_table[MAXCTLRS]; hw++) {
46 if (!HW_ISSCSI(hw))
47 continue;
48 hs = &scsi_softc[i];
49 hs->sc_addr = hw->hw_kva;
50 scsireset(i);
51 if (howto & RB_ASKNAME)
52 printf("scsi%d at sc%d\n", i, hw->hw_sc);
53 hw->hw_pa = (caddr_t) i; /* XXX for autoconfig */
54 hs->sc_alive = 1;
55 i++;
56 }
57 /*
58 * Adjust the wait values
59 */
60 if (!waitset) {
61 scsi_cmd_wait *= cpuspeed;
62 scsi_data_wait *= cpuspeed;
63 waitset = 1;
64 }
65 }
66
scsialive(unit)67 scsialive(unit)
68 register int unit;
69 {
70 if (unit >= NSCSI || scsi_softc[unit].sc_alive == 0)
71 return (0);
72 return (1);
73 }
74
75 void
scsireset(unit)76 scsireset(unit)
77 register int unit;
78 {
79 volatile register struct scsidevice *hd;
80 register struct scsi_softc *hs;
81 u_int i;
82
83 hs = &scsi_softc[unit];
84 hd = (struct scsidevice *)hs->sc_addr;
85 hd->scsi_id = 0xFF;
86 DELAY(100);
87 /*
88 * Disable interrupts then reset the FUJI chip.
89 */
90 hd->scsi_csr = 0;
91 hd->scsi_sctl = SCTL_DISABLE | SCTL_CTRLRST;
92 hd->scsi_scmd = 0;
93 hd->scsi_tmod = 0;
94 hd->scsi_pctl = 0;
95 hd->scsi_temp = 0;
96 hd->scsi_tch = 0;
97 hd->scsi_tcm = 0;
98 hd->scsi_tcl = 0;
99 hd->scsi_ints = 0;
100
101 /*
102 * Configure the FUJI chip with its SCSI address, all
103 * interrupts enabled & appropriate parity.
104 */
105 i = (~hd->scsi_hconf) & 0x7;
106 hs->sc_scsi_addr = 1 << i;
107 hd->scsi_bdid = i;
108 if (hd->scsi_hconf & HCONF_PARITY)
109 hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB |
110 SCTL_SEL_ENAB | SCTL_RESEL_ENAB |
111 SCTL_INTR_ENAB | SCTL_PARITY_ENAB;
112 else
113 hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB |
114 SCTL_SEL_ENAB | SCTL_RESEL_ENAB |
115 SCTL_INTR_ENAB;
116 hd->scsi_sctl &=~ SCTL_DISABLE;
117 }
118
119
120 int
scsiabort(hs,hd)121 scsiabort(hs, hd)
122 register struct scsi_softc *hs;
123 volatile register struct scsidevice *hd;
124 {
125 printf("scsi%d error: scsiabort\n", hs - scsi_softc);
126
127 scsireset(hs - scsi_softc);
128 DELAY(1000000);
129 }
130
131 static int
issue_select(hd,target,our_addr)132 issue_select(hd, target, our_addr)
133 volatile register struct scsidevice *hd;
134 u_char target, our_addr;
135 {
136 if (hd->scsi_ssts & (SSTS_INITIATOR|SSTS_TARGET|SSTS_BUSY))
137 return (1);
138
139 if (hd->scsi_ints & INTS_DISCON)
140 hd->scsi_ints = INTS_DISCON;
141
142 hd->scsi_pctl = 0;
143 hd->scsi_temp = (1 << target) | our_addr;
144 /* select timeout is hardcoded to 2ms */
145 hd->scsi_tch = 0;
146 hd->scsi_tcm = 32;
147 hd->scsi_tcl = 4;
148
149 hd->scsi_scmd = SCMD_SELECT;
150 return (0);
151 }
152
153 static int
wait_for_select(hd)154 wait_for_select(hd)
155 volatile register struct scsidevice *hd;
156 {
157 register int wait;
158 u_char ints;
159
160 wait = scsi_data_wait;
161 while ((ints = hd->scsi_ints) == 0) {
162 if (--wait < 0)
163 return (1);
164 DELAY(1);
165 }
166 hd->scsi_ints = ints;
167 return (!(hd->scsi_ssts & SSTS_INITIATOR));
168 }
169
170 static int
ixfer_start(hd,len,phase,wait)171 ixfer_start(hd, len, phase, wait)
172 volatile register struct scsidevice *hd;
173 int len;
174 u_char phase;
175 register int wait;
176 {
177
178 hd->scsi_tch = len >> 16;
179 hd->scsi_tcm = len >> 8;
180 hd->scsi_tcl = len;
181 hd->scsi_pctl = phase;
182 hd->scsi_tmod = 0; /*XXX*/
183 hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR;
184
185 /* wait for xfer to start or svc_req interrupt */
186 while ((hd->scsi_ssts & SSTS_BUSY) == 0) {
187 if (hd->scsi_ints || --wait < 0)
188 return (0);
189 DELAY(1);
190 }
191 return (1);
192 }
193
194 static int
ixfer_out(hd,len,buf)195 ixfer_out(hd, len, buf)
196 volatile register struct scsidevice *hd;
197 int len;
198 register u_char *buf;
199 {
200 register int wait = scsi_data_wait;
201
202 for (; len > 0; --len) {
203 while (hd->scsi_ssts & SSTS_DREG_FULL) {
204 if (hd->scsi_ints || --wait < 0)
205 return (len);
206 DELAY(1);
207 }
208 hd->scsi_dreg = *buf++;
209 }
210 return (0);
211 }
212
213 static int
ixfer_in(hd,len,buf)214 ixfer_in(hd, len, buf)
215 volatile register struct scsidevice *hd;
216 int len;
217 register u_char *buf;
218 {
219 register int wait = scsi_data_wait;
220
221 for (; len > 0; --len) {
222 while (hd->scsi_ssts & SSTS_DREG_EMPTY) {
223 if (hd->scsi_ints || --wait < 0) {
224 while (! (hd->scsi_ssts & SSTS_DREG_EMPTY)) {
225 *buf++ = hd->scsi_dreg;
226 --len;
227 }
228 return (len);
229 }
230 DELAY(1);
231 }
232 *buf++ = hd->scsi_dreg;
233 }
234 return (len);
235 }
236
237 static int
scsiicmd(hs,target,cbuf,clen,buf,len,xferphase)238 scsiicmd(hs, target, cbuf, clen, buf, len, xferphase)
239 struct scsi_softc *hs;
240 int target;
241 u_char *cbuf;
242 int clen;
243 u_char *buf;
244 int len;
245 u_char xferphase;
246 {
247 volatile register struct scsidevice *hd =
248 (struct scsidevice *)hs->sc_addr;
249 u_char phase, ints;
250 register int wait;
251
252 /* select the SCSI bus (it's an error if bus isn't free) */
253 if (issue_select(hd, target, hs->sc_scsi_addr))
254 return (-2);
255 if (wait_for_select(hd))
256 return (-2);
257 /*
258 * Wait for a phase change (or error) then let the device
259 * sequence us through the various SCSI phases.
260 */
261 hs->sc_stat = -1;
262 phase = CMD_PHASE;
263 while (1) {
264 wait = scsi_cmd_wait;
265 switch (phase) {
266
267 case CMD_PHASE:
268 if (ixfer_start(hd, clen, phase, wait))
269 if (ixfer_out(hd, clen, cbuf))
270 goto abort;
271 phase = xferphase;
272 break;
273
274 case DATA_IN_PHASE:
275 if (len <= 0)
276 goto abort;
277 wait = scsi_data_wait;
278 if (ixfer_start(hd, len, phase, wait) ||
279 !(hd->scsi_ssts & SSTS_DREG_EMPTY))
280 ixfer_in(hd, len, buf);
281 phase = STATUS_PHASE;
282 break;
283
284 case DATA_OUT_PHASE:
285 if (len <= 0)
286 goto abort;
287 wait = scsi_data_wait;
288 if (ixfer_start(hd, len, phase, wait))
289 if (ixfer_out(hd, len, buf))
290 goto abort;
291 phase = STATUS_PHASE;
292 break;
293
294 case STATUS_PHASE:
295 wait = scsi_data_wait;
296 if (ixfer_start(hd, sizeof(hs->sc_stat), phase, wait) ||
297 !(hd->scsi_ssts & SSTS_DREG_EMPTY))
298 ixfer_in(hd, sizeof(hs->sc_stat), &hs->sc_stat);
299 phase = MESG_IN_PHASE;
300 break;
301
302 case MESG_IN_PHASE:
303 if (ixfer_start(hd, sizeof(hs->sc_msg), phase, wait) ||
304 !(hd->scsi_ssts & SSTS_DREG_EMPTY)) {
305 ixfer_in(hd, sizeof(hs->sc_msg), &hs->sc_msg);
306 hd->scsi_scmd = SCMD_RST_ACK;
307 }
308 phase = BUS_FREE_PHASE;
309 break;
310
311 case BUS_FREE_PHASE:
312 goto out;
313
314 default:
315 printf("scsi%d: unexpected scsi phase %d\n",
316 hs - scsi_softc, phase);
317 goto abort;
318 }
319 #ifdef SLOWSCSI
320 /*
321 * XXX we have wierd transient problems with booting from
322 * slow scsi disks on fast machines. I have never been
323 * able to pin the problem down, but a large delay here
324 * seems to always work.
325 */
326 DELAY(1000);
327 #endif
328 /* wait for last command to complete */
329 while ((ints = hd->scsi_ints) == 0) {
330 if (--wait < 0)
331 goto abort;
332 DELAY(1);
333 }
334 hd->scsi_ints = ints;
335 if (ints & INTS_SRV_REQ)
336 phase = hd->scsi_psns & PHASE;
337 else if (ints & INTS_DISCON)
338 goto out;
339 else if ((ints & INTS_CMD_DONE) == 0)
340 goto abort;
341 }
342 abort:
343 scsiabort(hs, hd);
344 out:
345 return (hs->sc_stat);
346 }
347
348 int
scsi_test_unit_rdy(ctlr,slave)349 scsi_test_unit_rdy(ctlr, slave)
350 int ctlr, slave;
351 {
352 register struct scsi_softc *hs = &scsi_softc[ctlr];
353 static struct scsi_cdb6 cdb = { CMD_TEST_UNIT_READY };
354
355 return (scsiicmd(hs, slave, &cdb, sizeof(cdb), (u_char *)0, 0,
356 STATUS_PHASE));
357 }
358
359 int
scsi_request_sense(ctlr,slave,buf,len)360 scsi_request_sense(ctlr, slave, buf, len)
361 int ctlr, slave;
362 u_char *buf;
363 unsigned len;
364 {
365 register struct scsi_softc *hs = &scsi_softc[ctlr];
366 static struct scsi_cdb6 cdb = { CMD_REQUEST_SENSE };
367
368 cdb.len = len;
369 return (scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len,
370 DATA_IN_PHASE));
371 }
372
373 int
scsi_read_capacity(ctlr,slave,buf,len)374 scsi_read_capacity(ctlr, slave, buf, len)
375 int ctlr, slave;
376 u_char *buf;
377 unsigned len;
378 {
379 register struct scsi_softc *hs = &scsi_softc[ctlr];
380 static struct scsi_cdb10 cdb = { CMD_READ_CAPACITY };
381
382 return (scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len,
383 DATA_IN_PHASE));
384 }
385
386 int
scsi_tt_read(ctlr,slave,buf,len,blk,nblk)387 scsi_tt_read(ctlr, slave, buf, len, blk, nblk)
388 int ctlr, slave;
389 u_char *buf;
390 u_int len;
391 daddr_t blk;
392 u_int nblk;
393 {
394 register struct scsi_softc *hs = &scsi_softc[ctlr];
395 struct scsi_cdb10 cdb;
396
397 bzero(&cdb, sizeof(cdb));
398 cdb.cmd = CMD_READ_EXT;
399 cdb.lbah = blk >> 24;
400 cdb.lbahm = blk >> 16;
401 cdb.lbalm = blk >> 8;
402 cdb.lbal = blk;
403 cdb.lenh = nblk >> (8 + DEV_BSHIFT);
404 cdb.lenl = nblk >> DEV_BSHIFT;
405 return (scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len,
406 DATA_IN_PHASE));
407 }
408
409 int
scsi_tt_write(ctlr,slave,buf,len,blk,nblk)410 scsi_tt_write(ctlr, slave, buf, len, blk, nblk)
411 int ctlr, slave;
412 u_char *buf;
413 u_int len;
414 daddr_t blk;
415 u_int nblk;
416 {
417 register struct scsi_softc *hs = &scsi_softc[ctlr];
418 struct scsi_cdb10 cdb;
419
420 bzero(&cdb, sizeof(cdb));
421 cdb.cmd = CMD_WRITE_EXT;
422 cdb.lbah = blk >> 24;
423 cdb.lbahm = blk >> 16;
424 cdb.lbalm = blk >> 8;
425 cdb.lbal = blk;
426 cdb.lenh = nblk >> (8 + DEV_BSHIFT);
427 cdb.lenl = nblk >> DEV_BSHIFT;
428 return (scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len,
429 DATA_OUT_PHASE));
430 }
431