siop.c revision 1.4 1 /* $NetBSD: siop.c,v 1.4 2021/07/24 21:31:35 andvar Exp $ */
2 /*
3 * Copyright (c) 2010 KIYOHARA Takashi
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <lib/libsa/stand.h>
29 #include <lib/libkern/libkern.h>
30
31 #include <dev/microcode/siop/siop.out>
32
33 #include "boot.h"
34 #include "sdvar.h"
35
36 #define SIOP_DEFAULT_TARGET 7
37
38 #define ALLOC(T, A) \
39 (T *)(((uint32_t)alloc(sizeof(T) + (A)) + (A)) & ~((A) - 1))
40 #define VTOPHYS(va) (uint32_t)(va)
41 #define DEVTOV(pa) (uint32_t)(pa)
42 #define wbinv(adr, siz) _wbinv(VTOPHYS(adr), (uint32_t)(siz))
43 #define inv(adr, siz) _inv(VTOPHYS(adr), (uint32_t)(siz))
44
45 /* 53c810 supports little endian */
46 #define htoc32(x) htole32(x)
47 #define ctoh32(x) le32toh(x)
48
49 static void siop_pci_reset(int);
50
51 static void siop_setuptables(struct siop_adapter *, struct siop_xfer *,
52 struct scsi_xfer *);
53 static void siop_ma(struct siop_adapter *, struct scsi_xfer *);
54 static void siop_sdp(struct siop_adapter *, struct siop_xfer *,
55 struct scsi_xfer *, int);
56 static void siop_update_resid(struct siop_adapter *, struct siop_xfer *,
57 struct scsi_xfer *, int);
58
59 static int siop_intr(struct siop_adapter *);
60 static void siop_scsicmd_end(struct siop_adapter *, struct scsi_xfer *);
61 static int siop_scsi_request(struct siop_adapter *, struct scsi_xfer *);
62 static void siop_start(struct siop_adapter *, struct scsi_xfer *);
63 static void siop_xfer_setup(struct siop_xfer *, void *);
64
65 static int siop_add_reselsw(struct siop_adapter *, int, int);
66 static void siop_update_scntl3(struct siop_adapter *, int, int);
67
68 static int _scsi_inquire(struct siop_adapter *, int, int, int, char *);
69 static void scsi_request_sense(struct siop_adapter *, struct scsi_xfer *);
70 static int scsi_interpret_sense(struct siop_adapter *, struct scsi_xfer *);
71 static int scsi_probe(struct siop_adapter *);
72
73 static struct siop_adapter adapt;
74
75
76 static void
77 siop_pci_reset(int addr)
78 {
79 int dmode, ctest5;
80 const int maxburst = 4; /* 53c810 */
81
82 dmode = readb(addr + SIOP_DMODE);
83
84 ctest5 = readb(addr + SIOP_CTEST5);
85 writeb(addr + SIOP_CTEST4, readb(addr + SIOP_CTEST4) & ~CTEST4_BDIS);
86 ctest5 &= ~CTEST5_BBCK;
87 ctest5 |= (maxburst - 1) & CTEST5_BBCK;
88 writeb(addr + SIOP_CTEST5, ctest5);
89
90 dmode |= DMODE_ERL;
91 dmode &= ~DMODE_BL_MASK;
92 dmode |= ((maxburst - 1) << DMODE_BL_SHIFT) & DMODE_BL_MASK;
93 writeb(addr + SIOP_DMODE, dmode);
94 }
95
96
97 static void
98 siop_setuptables(struct siop_adapter *adp, struct siop_xfer *xfer,
99 struct scsi_xfer *xs)
100 {
101 int msgoffset = 1;
102
103 xfer->siop_tables.id =
104 htoc32((adp->clock_div << 24) | (xs->target << 16));
105 memset(xfer->siop_tables.msg_out, 0, sizeof(xfer->siop_tables.msg_out));
106 /* request sense doesn't disconnect */
107 if (xs->cmd->opcode == SCSI_REQUEST_SENSE)
108 xfer->siop_tables.msg_out[0] = MSG_IDENTIFY(xs->lun, 0);
109 else
110 xfer->siop_tables.msg_out[0] = MSG_IDENTIFY(xs->lun, 1);
111
112 xfer->siop_tables.t_msgout.count = htoc32(msgoffset);
113 xfer->siop_tables.status =
114 htoc32(SCSI_SIOP_NOSTATUS); /* set invalid status */
115
116 xfer->siop_tables.cmd.count = htoc32(xs->cmdlen);
117 xfer->siop_tables.cmd.addr = htoc32(local_to_PCI((u_long)xs->cmd));
118 if (xs->datalen != 0) {
119 xfer->siop_tables.data[0].count = htoc32(xs->datalen);
120 xfer->siop_tables.data[0].addr =
121 htoc32(local_to_PCI((u_long)xs->data));
122 }
123 }
124
125 static void
126 siop_ma(struct siop_adapter *adp, struct scsi_xfer *xs)
127 {
128 int offset, dbc;
129
130 /*
131 * compute how much of the current table didn't get handled when
132 * a phase mismatch occurs
133 */
134 if (xs->datalen == 0)
135 return; /* no valid data transfer */
136
137 offset = readb(adp->addr + SIOP_SCRATCHA + 1);
138 if (offset >= SIOP_NSG) {
139 printf("bad offset in siop_sdp (%d)\n", offset);
140 return;
141 }
142 dbc = readl(adp->addr + SIOP_DBC) & 0x00ffffff;
143 xs->resid = dbc;
144 }
145
146 static void
147 siop_sdp(struct siop_adapter *adp, struct siop_xfer *xfer, struct scsi_xfer *xs,
148 int offset)
149 {
150
151 if (xs->datalen == 0)
152 return; /* no data pointers to save */
153
154 /*
155 * offset == SIOP_NSG may be a valid condition if we get a Save data
156 * pointer when the xfer is done. Just ignore the Save data pointer
157 * in this case
158 */
159 if (offset == SIOP_NSG)
160 return;
161 /*
162 * Save data pointer. We do this by adjusting the tables to point
163 * at the beginning of the data not yet transferred.
164 * offset points to the first table with untransferred data.
165 */
166
167 /*
168 * before doing that we decrease resid from the amount of data which
169 * has been transferred.
170 */
171 siop_update_resid(adp, xfer, xs, offset);
172
173 #if 0
174 /*
175 * First let see if we have a resid from a phase mismatch. If so,
176 * we have to adjust the table at offset to remove transferred data.
177 */
178 if (siop_cmd->flags & CMDFL_RESID) {
179 scr_table_t *table;
180
181 siop_cmd->flags &= ~CMDFL_RESID;
182 table = &xfer->siop_tables.data[offset];
183 /* "cut" already transfered data from this table */
184 table->addr =
185 htoc32(ctoh32(table->addr) + ctoh32(table->count) -
186 siop_cmd->resid);
187 table->count = htoc32(siop_cmd->resid);
188 }
189 #endif
190
191 /*
192 * now we can remove entries which have been transferred.
193 * We just move the entries with data left at the beginning of the
194 * tables
195 */
196 memmove(xfer->siop_tables.data, &xfer->siop_tables.data[offset],
197 (SIOP_NSG - offset) * sizeof(scr_table_t));
198 }
199
200 static void
201 siop_update_resid(struct siop_adapter *adp, struct siop_xfer *xfer,
202 struct scsi_xfer *xs, int offset)
203 {
204 int i;
205
206 if (xs->datalen == 0)
207 return; /* no data to transfer */
208
209 /*
210 * update resid. First account for the table entries which have
211 * been fully completed.
212 */
213 for (i = 0; i < offset; i++)
214 xs->resid -= ctoh32(xfer->siop_tables.data[i].count);
215 #if 0
216 /*
217 * if CMDFL_RESID is set, the last table (pointed by offset) is a
218 * partial transfers. If not, offset points to the entry folloing
219 * the last full transfer.
220 */
221 if (siop_cmd->flags & CMDFL_RESID) {
222 scr_table_t *table = &xfer->siop_tables.data[offset];
223
224 xs->resid -= ctoh32(table->count) - xs->resid;
225 }
226 #endif
227 }
228
229
230 #define CALL_SCRIPT(ent) writel(adp->addr + SIOP_DSP, scriptaddr + ent);
231
232 static int
233 siop_intr(struct siop_adapter *adp)
234 {
235 struct siop_xfer *siop_xfer = NULL;
236 struct scsi_xfer *xs = NULL;
237 u_long scriptaddr = local_to_PCI((u_long)adp->script);
238 int offset, target, lun, tag, restart = 0, need_reset = 0;
239 uint32_t dsa, irqcode;
240 uint16_t sist;
241 uint8_t dstat = 0, sstat1, istat;
242
243 istat = readb(adp->addr + SIOP_ISTAT);
244 if ((istat & (ISTAT_INTF | ISTAT_DIP | ISTAT_SIP)) == 0)
245 return 0;
246 if (istat & ISTAT_INTF) {
247 printf("INTRF\n");
248 writeb(adp->addr + SIOP_ISTAT, ISTAT_INTF);
249 }
250 if ((istat & (ISTAT_DIP | ISTAT_SIP | ISTAT_ABRT)) ==
251 (ISTAT_DIP | ISTAT_ABRT))
252 /* clear abort */
253 writeb(adp->addr + SIOP_ISTAT, 0);
254 /* use DSA to find the current siop_cmd */
255 dsa = readl(adp->addr + SIOP_DSA);
256 if (dsa >= local_to_PCI((u_long)adp->xfer) &&
257 dsa < local_to_PCI((u_long)adp->xfer) + SIOP_TABLE_SIZE) {
258 dsa -= local_to_PCI((u_long)adp->xfer);
259 siop_xfer = adp->xfer;
260 _inv((u_long)siop_xfer, sizeof(*siop_xfer));
261
262 xs = adp->xs;
263 }
264
265 if (istat & ISTAT_DIP)
266 dstat = readb(adp->addr + SIOP_DSTAT);
267 if (istat & ISTAT_SIP) {
268 if (istat & ISTAT_DIP)
269 delay(10);
270 /*
271 * Can't read sist0 & sist1 independently, or we have to
272 * insert delay
273 */
274 sist = readw(adp->addr + SIOP_SIST0);
275 sstat1 = readb(adp->addr + SIOP_SSTAT1);
276
277 if ((sist & SIST0_MA) && need_reset == 0) {
278 if (siop_xfer) {
279 int scratcha0;
280
281 dstat = readb(adp->addr + SIOP_DSTAT);
282 /*
283 * first restore DSA, in case we were in a S/G
284 * operation.
285 */
286 writel(adp->addr + SIOP_DSA,
287 local_to_PCI((u_long)siop_xfer));
288 scratcha0 = readb(adp->addr + SIOP_SCRATCHA);
289 switch (sstat1 & SSTAT1_PHASE_MASK) {
290 case SSTAT1_PHASE_STATUS:
291 /*
292 * previous phase may be aborted for any reason
293 * ( for example, the target has less data to
294 * transfer than requested). Compute resid and
295 * just go to status, the command should
296 * terminate.
297 */
298 if (scratcha0 & A_flag_data)
299 siop_ma(adp, xs);
300 else if ((dstat & DSTAT_DFE) == 0)
301 printf("PHASE STATUS: siop_clearfifo...\n");
302 // siop_clearfifo(adp);
303 CALL_SCRIPT(Ent_status);
304 return 1;
305 case SSTAT1_PHASE_MSGIN:
306 /*
307 * target may be ready to disconnect
308 * Compute resid which would be used later
309 * if a save data pointer is needed.
310 */
311 if (scratcha0 & A_flag_data)
312 siop_ma(adp, xs);
313 else if ((dstat & DSTAT_DFE) == 0)
314 printf("PHASE MSGIN: siop_clearfifo...\n");
315 // siop_clearfifo(adp);
316 writeb(adp->addr + SIOP_SCRATCHA,
317 scratcha0 & ~A_flag_data);
318 CALL_SCRIPT(Ent_msgin);
319 return 1;
320 }
321 printf("unexpected phase mismatch %d\n",
322 sstat1 & SSTAT1_PHASE_MASK);
323 } else
324 printf("phase mismatch without command\n");
325 need_reset = 1;
326 }
327 if (sist & (SIST1_STO << 8)) {
328 /* selection time out, assume there's no device here */
329 if (siop_xfer) {
330 xs->error = XS_SELTIMEOUT;
331 goto end;
332 } else
333 printf("selection timeout without command\n");
334 }
335
336 /* Else it's an unhandled exception (for now). */
337 printf("unhandled scsi interrupt,"
338 " sist=0x%x sstat1=0x%x DSA=0x%x DSP=0x%lx\n",
339 sist, sstat1, dsa,
340 readl(adp->addr + SIOP_DSP) - scriptaddr);
341 if (siop_xfer) {
342 xs->error = XS_SELTIMEOUT;
343 goto end;
344 }
345 need_reset = 1;
346 }
347 if (need_reset) {
348 reset:
349 printf("XXXXX: fatal error, need reset the bus...\n");
350 return 1;
351 }
352
353 //scintr:
354 if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) { /* script interrupt */
355 irqcode = readl(adp->addr + SIOP_DSPS);
356 /*
357 * no command, or an inactive command is only valid for a
358 * reselect interrupt
359 */
360 if ((irqcode & 0x80) == 0) {
361 if (siop_xfer == NULL) {
362 printf(
363 "script interrupt 0x%x with invalid DSA\n",
364 irqcode);
365 goto reset;
366 }
367 }
368 switch(irqcode) {
369 case A_int_err:
370 printf("error, DSP=0x%lx\n",
371 readl(adp->addr + SIOP_DSP) - scriptaddr);
372 if (xs) {
373 xs->error = XS_SELTIMEOUT;
374 goto end;
375 } else {
376 goto reset;
377 }
378 case A_int_reseltarg:
379 printf("reselect with invalid target\n");
380 goto reset;
381 case A_int_resellun:
382 target = readb(adp->addr + SIOP_SCRATCHA) & 0xf;
383 lun = readb(adp->addr + SIOP_SCRATCHA + 1);
384 tag = readb(adp->addr + SIOP_SCRATCHA + 2);
385 if (target != adp->xs->target ||
386 lun != adp->xs->lun ||
387 tag != 0) {
388 printf("unknwon resellun:"
389 " target %d lun %d tag %d\n",
390 target, lun, tag);
391 goto reset;
392 }
393 siop_xfer = adp->xfer;
394 dsa = local_to_PCI((u_long)siop_xfer);
395 writel(adp->addr + SIOP_DSP,
396 dsa + sizeof(struct siop_common_xfer) +
397 Ent_ldsa_reload_dsa);
398 _wbinv((u_long)siop_xfer, sizeof(*siop_xfer));
399 return 1;
400 case A_int_reseltag:
401 printf("reselect with invalid tag\n");
402 goto reset;
403 case A_int_disc:
404 offset = readb(adp->addr + SIOP_SCRATCHA + 1);
405 siop_sdp(adp, siop_xfer, xs, offset);
406 #if 0
407 /* we start again with no offset */
408 siop_cmd->saved_offset = SIOP_NOOFFSET;
409 #endif
410 _wbinv((u_long)siop_xfer, sizeof(*siop_xfer));
411 CALL_SCRIPT(Ent_script_sched);
412 return 1;
413 case A_int_resfail:
414 printf("reselect failed\n");
415 return 1;
416 case A_int_done:
417 if (xs == NULL) {
418 printf("done without command, DSA=0x%lx\n",
419 local_to_PCI((u_long)adp->xfer));
420 return 1;
421 }
422 /* update resid. */
423 offset = readb(adp->addr + SIOP_SCRATCHA + 1);
424 #if 0
425 /*
426 * if we got a disconnect between the last data phase
427 * and the status phase, offset will be 0. In this
428 * case, siop_cmd->saved_offset will have the proper
429 * value if it got updated by the controller
430 */
431 if (offset == 0 &&
432 siop_cmd->saved_offset != SIOP_NOOFFSET)
433 offset = siop_cmd->saved_offset;
434 #endif
435 siop_update_resid(adp, siop_xfer, xs, offset);
436 goto end;
437 default:
438 printf("unknown irqcode %x\n", irqcode);
439 if (xs) {
440 xs->error = XS_SELTIMEOUT;
441 goto end;
442 }
443 goto reset;
444 }
445 return 1;
446 }
447 /* We just should't get there */
448 panic("siop_intr: I shouldn't be there !");
449
450 return 1;
451
452 end:
453 /*
454 * restart the script now if command completed properly
455 * Otherwise wait for siop_scsicmd_end(), we may need to cleanup the
456 * queue
457 */
458 xs->status = ctoh32(siop_xfer->siop_tables.status);
459 if (xs->status == SCSI_OK)
460 writel(adp->addr + SIOP_DSP, scriptaddr + Ent_script_sched);
461 else
462 restart = 1;
463 siop_scsicmd_end(adp, xs);
464 if (restart)
465 writel(adp->addr + SIOP_DSP, scriptaddr + Ent_script_sched);
466
467 return 1;
468 }
469
470 static void
471 siop_scsicmd_end(struct siop_adapter *adp, struct scsi_xfer *xs)
472 {
473
474 switch(xs->status) {
475 case SCSI_OK:
476 xs->error = XS_NOERROR;
477 break;
478 case SCSI_BUSY:
479 case SCSI_CHECK:
480 case SCSI_QUEUE_FULL:
481 xs->error = XS_BUSY;
482 break;
483 case SCSI_SIOP_NOCHECK:
484 /*
485 * don't check status, xs->error is already valid
486 */
487 break;
488 case SCSI_SIOP_NOSTATUS:
489 /*
490 * the status byte was not updated, cmd was
491 * aborted
492 */
493 xs->error = XS_SELTIMEOUT;
494 break;
495 default:
496 printf("invalid status code %d\n", xs->status);
497 xs->error = XS_DRIVER_STUFFUP;
498 }
499 _inv((u_long)xs->cmd, xs->cmdlen);
500 if (xs->datalen != 0)
501 _inv((u_long)xs->data, xs->datalen);
502 xs->xs_status = XS_STS_DONE;
503 }
504
505 static int
506 siop_scsi_request(struct siop_adapter *adp, struct scsi_xfer *xs)
507 {
508 void *xfer = adp->xfer;
509 int timo, error;
510
511 if (adp->sel_t != xs->target) {
512 const int free_lo = __arraycount(siop_script);
513 int i;
514 void *scriptaddr = (void *)local_to_PCI((u_long)adp->script);
515
516 if (adp->sel_t != -1)
517 adp->script[Ent_resel_targ0 / 4 + adp->sel_t * 2] =
518 htoc32(0x800c00ff);
519
520 for (i = 0; i < __arraycount(lun_switch); i++)
521 adp->script[free_lo + i] = htoc32(lun_switch[i]);
522 adp->script[free_lo + E_abs_lunsw_return_Used[0]] =
523 htoc32(scriptaddr + Ent_lunsw_return);
524
525 siop_add_reselsw(adp, xs->target, free_lo);
526
527 adp->sel_t = xs->target;
528 }
529
530 restart:
531
532 siop_setuptables(adp, xfer, xs);
533
534 /* load the DMA maps */
535 if (xs->datalen != 0)
536 _inv((u_long)xs->data, xs->datalen);
537 _wbinv((u_long)xs->cmd, xs->cmdlen);
538
539 _wbinv((u_long)xfer, sizeof(struct siop_xfer));
540 siop_start(adp, xs);
541
542 adp->xs = xs;
543 timo = 0;
544 while (!(xs->xs_status & XS_STS_DONE)) {
545 delay(1000);
546 siop_intr(adp);
547
548 if (timo++ > 3000) { /* XXXX: 3sec */
549 printf("%s: timeout\n", __func__);
550 return ETIMEDOUT;
551 }
552 }
553
554 if (xs->error != XS_NOERROR) {
555 if (xs->error == XS_BUSY || xs->status == SCSI_CHECK)
556 scsi_request_sense(adp, xs);
557
558 switch (xs->error) {
559 case XS_SENSE:
560 case XS_SHORTSENSE:
561 error = scsi_interpret_sense(adp, xs);
562 break;
563 case XS_RESOURCE_SHORTAGE:
564 printf("adapter resource shortage\n");
565
566 /* FALLTHROUGH */
567 case XS_BUSY:
568 error = EBUSY;
569 break;
570 case XS_REQUEUE:
571 printf("XXXX: requeue...\n");
572 error = ERESTART;
573 break;
574 case XS_SELTIMEOUT:
575 case XS_TIMEOUT:
576 error = EIO;
577 break;
578 case XS_RESET:
579 error = EIO;
580 break;
581 case XS_DRIVER_STUFFUP:
582 printf("generic HBA error\n");
583 error = EIO;
584 break;
585 default:
586 printf("invalid return code from adapter: %d\n",
587 xs->error);
588 error = EIO;
589 break;
590 }
591 if (error == ERESTART) {
592 xs->error = XS_NOERROR;
593 xs->status = SCSI_OK;
594 xs->xs_status &= ~XS_STS_DONE;
595 goto restart;
596 }
597 return error;
598 }
599 return 0;
600 }
601
602 static void
603 siop_start(struct siop_adapter *adp, struct scsi_xfer *xs)
604 {
605 struct siop_xfer *siop_xfer = adp->xfer;
606 uint32_t dsa, *script = adp->script;
607 int slot;
608 void *scriptaddr = (void *)local_to_PCI((u_long)script);
609 const int siop_common_xfer_size = sizeof(struct siop_common_xfer);
610
611 /*
612 * The queue management here is a bit tricky: the script always looks
613 * at the slot from first to last, so if we always use the first
614 * free slot commands can stay at the tail of the queue ~forever.
615 * The algorithm used here is to restart from the head when we know
616 * that the queue is empty, and only add commands after the last one.
617 * When we're at the end of the queue wait for the script to clear it.
618 * The best thing to do here would be to implement a circular queue,
619 * but using only 53c720 features this can be "interesting".
620 * A mid-way solution could be to implement 2 queues and swap orders.
621 */
622 slot = adp->currschedslot;
623 /*
624 * If the instruction is 0x80000000 (JUMP foo, IF FALSE) the slot is
625 * free. As this is the last used slot, all previous slots are free,
626 * we can restart from 0.
627 */
628 if (ctoh32(script[(Ent_script_sched_slot0 / 4) + slot * 2]) ==
629 0x80000000) {
630 slot = adp->currschedslot = 0;
631 } else {
632 slot++;
633 }
634 /*
635 * find a free scheduler slot and load it.
636 */
637 #define SIOP_NSLOTS 0x40
638 for (; slot < SIOP_NSLOTS; slot++) {
639 /*
640 * If cmd if 0x80000000 the slot is free
641 */
642 if (ctoh32(script[(Ent_script_sched_slot0 / 4) + slot * 2]) ==
643 0x80000000)
644 break;
645 }
646 if (slot == SIOP_NSLOTS) {
647 /*
648 * no more free slot, no need to continue. freeze the queue
649 * and requeue this command.
650 */
651 printf("no mode free slot\n");
652 return;
653 }
654
655 /* patch scripts with DSA addr */
656 dsa = local_to_PCI((u_long)siop_xfer);
657
658 /* CMD script: MOVE MEMORY addr */
659 siop_xfer->resel[E_ldsa_abs_slot_Used[0]] =
660 htoc32(scriptaddr + Ent_script_sched_slot0 + slot * 8);
661 _wbinv((u_long)siop_xfer, sizeof(*siop_xfer));
662 /* scheduler slot: JUMP ldsa_select */
663 script[(Ent_script_sched_slot0 / 4) + slot * 2 + 1] =
664 htoc32(dsa + siop_common_xfer_size + Ent_ldsa_select);
665 /*
666 * Change JUMP cmd so that this slot will be handled
667 */
668 script[(Ent_script_sched_slot0 / 4) + slot * 2] = htoc32(0x80080000);
669 adp->currschedslot = slot;
670
671 /* make sure SCRIPT processor will read valid data */
672 _wbinv((u_long)script, SIOP_SCRIPT_SIZE);
673 /* Signal script it has some work to do */
674 writeb(adp->addr + SIOP_ISTAT, ISTAT_SIGP);
675 /* and wait for IRQ */
676 }
677
678 static void
679 siop_xfer_setup(struct siop_xfer *xfer, void *scriptaddr)
680 {
681 const int off_msg_in = offsetof(struct siop_common_xfer, msg_in);
682 const int off_status = offsetof(struct siop_common_xfer, status);
683 uint32_t dsa, *scr;
684 int i;
685
686 memset(xfer, 0, sizeof(*xfer));
687 dsa = local_to_PCI((u_long)xfer);
688 xfer->siop_tables.t_msgout.count = htoc32(1);
689 xfer->siop_tables.t_msgout.addr = htoc32(dsa);
690 xfer->siop_tables.t_msgin.count = htoc32(1);
691 xfer->siop_tables.t_msgin.addr = htoc32(dsa + off_msg_in);
692 xfer->siop_tables.t_extmsgin.count = htoc32(2);
693 xfer->siop_tables.t_extmsgin.addr = htoc32(dsa + off_msg_in + 1);
694 xfer->siop_tables.t_extmsgdata.addr = htoc32(dsa + off_msg_in + 3);
695 xfer->siop_tables.t_status.count = htoc32(1);
696 xfer->siop_tables.t_status.addr = htoc32(dsa + off_status);
697
698 /* The select/reselect script */
699 scr = xfer->resel;
700 for (i = 0; i < __arraycount(load_dsa); i++)
701 scr[i] = htoc32(load_dsa[i]);
702
703 /*
704 * 0x78000000 is a 'move data8 to reg'. data8 is the second
705 * octet, reg offset is the third.
706 */
707 scr[Ent_rdsa0 / 4] = htoc32(0x78100000 | ((dsa & 0x000000ff) << 8));
708 scr[Ent_rdsa1 / 4] = htoc32(0x78110000 | ( dsa & 0x0000ff00 ));
709 scr[Ent_rdsa2 / 4] = htoc32(0x78120000 | ((dsa & 0x00ff0000) >> 8));
710 scr[Ent_rdsa3 / 4] = htoc32(0x78130000 | ((dsa & 0xff000000) >> 16));
711 scr[E_ldsa_abs_reselected_Used[0]] =
712 htoc32(scriptaddr + Ent_reselected);
713 scr[E_ldsa_abs_reselect_Used[0]] = htoc32(scriptaddr + Ent_reselect);
714 scr[E_ldsa_abs_selected_Used[0]] = htoc32(scriptaddr + Ent_selected);
715 scr[E_ldsa_abs_data_Used[0]] =
716 htoc32(dsa + sizeof(struct siop_common_xfer) + Ent_ldsa_data);
717 /* JUMP foo, IF FALSE - used by MOVE MEMORY to clear the slot */
718 scr[Ent_ldsa_data / 4] = htoc32(0x80000000);
719 }
720
721 static int
722 siop_add_reselsw(struct siop_adapter *adp, int target, int lunsw_off)
723 {
724 uint32_t *script = adp->script;
725 int reseloff;
726 void *scriptaddr = (void *)local_to_PCI((u_long)adp->script);
727
728 /*
729 * add an entry to resel switch
730 */
731 reseloff = Ent_resel_targ0 / 4 + target * 2;
732 if ((ctoh32(script[reseloff]) & 0xff) != 0xff) {
733 /* it's not free */
734 printf("siop: resel switch full\n");
735 return EBUSY;
736 }
737
738 /* JUMP abs_foo, IF target | 0x80; */
739 script[reseloff + 0] = htoc32(0x800c0080 | target);
740 script[reseloff + 1] =
741 htoc32(scriptaddr + lunsw_off * 4 + Ent_lun_switch_entry);
742
743 siop_update_scntl3(adp, target, lunsw_off);
744 return 0;
745 }
746
747 static void
748 siop_update_scntl3(struct siop_adapter *adp, int target, int lunsw_off)
749 {
750 uint32_t *script = adp->script;
751
752 /* MOVE target->id >> 24 TO SCNTL3 */
753 script[lunsw_off + (Ent_restore_scntl3 / 4)] =
754 htoc32(0x78030000 | ((adp->clock_div >> 16) & 0x0000ff00));
755 /* MOVE target->id >> 8 TO SXFER */
756 script[lunsw_off + (Ent_restore_scntl3 / 4) + 2] =
757 htoc32(0x78050000 | (0x000000000 & 0x0000ff00));
758 _wbinv((u_long)script, SIOP_SCRIPT_SIZE);
759 }
760
761
762 /*
763 * SCSI functions
764 */
765
766 static int
767 _scsi_inquire(struct siop_adapter *adp, int t, int l, int buflen, char *buf)
768 {
769 struct scsipi_inquiry *cmd = (struct scsipi_inquiry *)adp->cmd;
770 struct scsipi_inquiry_data *inqbuf =
771 (struct scsipi_inquiry_data *)adp->data;
772 struct scsi_xfer xs;
773 int error;
774
775 memset(cmd, 0, sizeof(*cmd));
776 cmd->opcode = INQUIRY;
777 cmd->length = SCSIPI_INQUIRY_LENGTH_SCSI2;
778 memset(inqbuf, 0, sizeof(*inqbuf));
779
780 memset(&xs, 0, sizeof(xs));
781 xs.target = t;
782 xs.lun = l;
783 xs.cmdlen = sizeof(*cmd);
784 xs.cmd = (void *)cmd;
785 xs.datalen = SCSIPI_INQUIRY_LENGTH_SCSI2;
786 xs.data = (void *)inqbuf;
787
788 xs.error = XS_NOERROR;
789 xs.resid = xs.datalen;
790 xs.status = SCSI_OK;
791
792 error = siop_scsi_request(adp, &xs);
793 if (error != 0)
794 return error;
795
796 memcpy(buf, inqbuf, buflen);
797 return 0;
798 }
799
800 static void
801 scsi_request_sense(struct siop_adapter *adp, struct scsi_xfer *xs)
802 {
803 struct scsi_request_sense *cmd = adp->sense;
804 struct scsi_sense_data *data = (struct scsi_sense_data *)adp->data;
805 struct scsi_xfer sense;
806 int error;
807
808 memset(cmd, 0, sizeof(struct scsi_request_sense));
809 cmd->opcode = SCSI_REQUEST_SENSE;
810 cmd->length = sizeof(struct scsi_sense_data);
811 memset(data, 0, sizeof(struct scsi_sense_data));
812
813 memset(&sense, 0, sizeof(sense));
814 sense.target = xs->target;
815 sense.lun = xs->lun;
816 sense.cmdlen = sizeof(struct scsi_request_sense);
817 sense.cmd = (void *)cmd;
818 sense.datalen = sizeof(struct scsi_sense_data);
819 sense.data = (void *)data;
820
821 sense.error = XS_NOERROR;
822 sense.resid = sense.datalen;
823 sense.status = SCSI_OK;
824
825 error = siop_scsi_request(adp, &sense);
826 switch (error) {
827 case 0:
828 /* we have a valid sense */
829 xs->error = XS_SENSE;
830 return;
831 case EINTR:
832 /* REQUEST_SENSE interrupted by bus reset. */
833 xs->error = XS_RESET;
834 return;
835 case EIO:
836 /* request sense couldn't be performed */
837 /*
838 * XXX this isn't quite right but we don't have anything
839 * better for now
840 */
841 xs->error = XS_DRIVER_STUFFUP;
842 return;
843 default:
844 /* Notify that request sense failed. */
845 xs->error = XS_DRIVER_STUFFUP;
846 printf("request sense failed with error %d\n", error);
847 return;
848 }
849 }
850
851 /*
852 * scsi_interpret_sense:
853 *
854 * Look at the returned sense and act on the error, determining
855 * the unix error number to pass back. (0 = report no error)
856 *
857 * NOTE: If we return ERESTART, we are expected to have
858 * thawed the device!
859 *
860 * THIS IS THE DEFAULT ERROR HANDLER FOR SCSI DEVICES.
861 */
862 static int
863 scsi_interpret_sense(struct siop_adapter *adp, struct scsi_xfer *xs)
864 {
865 struct scsi_sense_data *sense;
866 u_int8_t key;
867 int error = 0;
868 uint32_t info;
869 static const char *error_mes[] = {
870 "soft error (corrected)",
871 "not ready", "medium error",
872 "non-media hardware failure", "illegal request",
873 "unit attention", "readonly device",
874 "no data found", "vendor unique",
875 "copy aborted", "command aborted",
876 "search returned equal", "volume overflow",
877 "verify miscompare", "unknown error key"
878 };
879
880 sense = (struct scsi_sense_data *)xs->data;
881
882 /* otherwise use the default */
883 switch (SSD_RCODE(sense->response_code)) {
884
885 /*
886 * Old SCSI-1 and SASI devices respond with
887 * codes other than 70.
888 */
889 case 0x00: /* no error (command completed OK) */
890 return 0;
891 case 0x04: /* drive not ready after it was selected */
892 if (adp->sd->sc_flags & FLAGS_REMOVABLE)
893 adp->sd->sc_flags &= ~FLAGS_MEDIA_LOADED;
894 /* XXX - display some sort of error here? */
895 return EIO;
896 case 0x20: /* invalid command */
897 return EINVAL;
898 case 0x25: /* invalid LUN (Adaptec ACB-4000) */
899 return EACCES;
900
901 /*
902 * If it's code 70, use the extended stuff and
903 * interpret the key
904 */
905 case 0x71: /* delayed error */
906 key = SSD_SENSE_KEY(sense->flags);
907 printf(" DEFERRED ERROR, key = 0x%x\n", key);
908 /* FALLTHROUGH */
909 case 0x70:
910 if ((sense->response_code & SSD_RCODE_VALID) != 0)
911 info = _4btol(sense->info);
912 else
913 info = 0;
914 key = SSD_SENSE_KEY(sense->flags);
915
916 switch (key) {
917 case SKEY_NO_SENSE:
918 case SKEY_RECOVERED_ERROR:
919 if (xs->resid == xs->datalen && xs->datalen) {
920 /*
921 * Why is this here?
922 */
923 xs->resid = 0; /* not short read */
924 }
925 case SKEY_EQUAL:
926 break;
927 case SKEY_NOT_READY:
928 if (adp->sd->sc_flags & FLAGS_REMOVABLE)
929 adp->sd->sc_flags &= ~FLAGS_MEDIA_LOADED;
930 if (sense->asc == 0x3A) {
931 error = ENODEV; /* Medium not present */
932 } else
933 error = EIO;
934 break;
935 case SKEY_ILLEGAL_REQUEST:
936 error = EINVAL;
937 break;
938 case SKEY_UNIT_ATTENTION:
939 if (sense->asc == 0x29 &&
940 sense->ascq == 0x00) {
941 /* device or bus reset */
942 return ERESTART;
943 }
944 if (adp->sd->sc_flags & FLAGS_REMOVABLE)
945 adp->sd->sc_flags &= ~FLAGS_MEDIA_LOADED;
946 if (!(adp->sd->sc_flags & FLAGS_REMOVABLE))
947 return ERESTART;
948 error = EIO;
949 break;
950 case SKEY_DATA_PROTECT:
951 error = EROFS;
952 break;
953 case SKEY_BLANK_CHECK:
954 break;
955 case SKEY_ABORTED_COMMAND:
956 break;
957 case SKEY_VOLUME_OVERFLOW:
958 error = ENOSPC;
959 break;
960 default:
961 error = EIO;
962 break;
963 }
964
965 /* Print brief(er) sense information */
966 printf("%s", error_mes[key - 1]);
967 if ((sense->response_code & SSD_RCODE_VALID) != 0) {
968 switch (key) {
969 case SKEY_NOT_READY:
970 case SKEY_ILLEGAL_REQUEST:
971 case SKEY_UNIT_ATTENTION:
972 case SKEY_DATA_PROTECT:
973 break;
974 case SKEY_BLANK_CHECK:
975 printf(", requested size: %d (decimal)",
976 info);
977 break;
978 case SKEY_ABORTED_COMMAND:
979 printf(", cmd 0x%x, info 0x%x",
980 xs->cmd->opcode, info);
981 break;
982 default:
983 printf(", info = %d (decimal)", info);
984 }
985 }
986 if (sense->extra_len != 0) {
987 int n;
988 printf(", data =");
989 for (n = 0; n < sense->extra_len; n++)
990 printf(" %x", sense->csi[n]);
991 }
992 printf("\n");
993 return error;
994
995 /*
996 * Some other code, just report it
997 */
998 default:
999 printf("Sense Error Code 0x%x",
1000 SSD_RCODE(sense->response_code));
1001 if ((sense->response_code & SSD_RCODE_VALID) != 0) {
1002 struct scsi_sense_data_unextended *usense =
1003 (struct scsi_sense_data_unextended *)sense;
1004 printf(" at block no. %d (decimal)",
1005 _3btol(usense->block));
1006 }
1007 printf("\n");
1008 return EIO;
1009 }
1010 }
1011
1012 static int
1013 scsi_probe(struct siop_adapter *adp)
1014 {
1015 struct scsipi_inquiry_data *inqbuf;
1016 int found, t, l;
1017 uint8_t device;
1018 char buf[SCSIPI_INQUIRY_LENGTH_SCSI2],
1019 product[sizeof(inqbuf->product) + 1];
1020
1021 found = 0;
1022 for (t = 0; t < 8; t++) {
1023 if (t == adp->id)
1024 continue;
1025 for (l = 0; l < 8; l++) {
1026 if (_scsi_inquire(adp, t, l, sizeof(buf), buf) != 0)
1027 continue;
1028
1029 inqbuf = (struct scsipi_inquiry_data *)buf;
1030 device = inqbuf->device & SID_TYPE;
1031 if (device == T_NODEVICE)
1032 continue;
1033 if (device != T_DIRECT &&
1034 device != T_OPTICAL &&
1035 device != T_SIMPLE_DIRECT)
1036 continue;
1037
1038 memset(product, 0, sizeof(product));
1039 strncpy(product, inqbuf->product, sizeof(product) - 1);
1040 printf("sd(%d,%d,[0-7]): <%s>\n", t, l, product);
1041 found++;
1042 }
1043 }
1044 return found;
1045 }
1046
1047 int
1048 scsi_inquire(struct sd_softc *sd, int buflen, void *buf)
1049 {
1050 struct siop_adapter *adp;
1051 int error;
1052
1053 if (sd->sc_bus != 0)
1054 return ENOTSUP;
1055 if (adapt.addr == 0xffffffff)
1056 return ENOENT;
1057 adp = &adapt;
1058
1059 adp->sd = sd;
1060 error = _scsi_inquire(adp, sd->sc_target, sd->sc_lun, buflen, buf);
1061 adp->sd = NULL;
1062
1063 return error;
1064 }
1065
1066 /*
1067 * scsi_mode_sense
1068 * get a sense page from a device
1069 */
1070
1071 int
1072 scsi_mode_sense(struct sd_softc *sd, int byte2, int page,
1073 struct scsi_mode_parameter_header_6 *data, int len)
1074 {
1075 struct scsi_mode_sense_6 cmd;
1076
1077 memset(&cmd, 0, sizeof(cmd));
1078 cmd.opcode = SCSI_MODE_SENSE_6;
1079 cmd.byte2 = byte2;
1080 cmd.page = page;
1081 cmd.length = len & 0xff;
1082
1083 return scsi_command(sd, (void *)&cmd, sizeof(cmd), (void *)data, len);
1084 }
1085
1086 int
1087 scsi_command(struct sd_softc *sd, void *cmd, int cmdlen, void *data,
1088 int datalen)
1089 {
1090 struct siop_adapter *adp;
1091 struct scsi_xfer xs;
1092 int error;
1093
1094 if (sd->sc_bus != 0)
1095 return ENOTSUP;
1096 if (adapt.addr == 0xffffffff)
1097 return ENOENT;
1098 adp = &adapt;
1099
1100 memcpy(adp->cmd, cmd, cmdlen);
1101 adp->sd = sd;
1102
1103 memset(&xs, 0, sizeof(xs));
1104 xs.target = sd->sc_target;
1105 xs.lun = sd->sc_lun;
1106 xs.cmdlen = cmdlen;
1107 xs.cmd = adp->cmd;
1108 xs.datalen = datalen;
1109 xs.data = adp->data;
1110
1111 xs.error = XS_NOERROR;
1112 xs.resid = datalen;
1113 xs.status = SCSI_OK;
1114
1115 error = siop_scsi_request(adp, &xs);
1116 adp->sd = NULL;
1117 if (error != 0)
1118 return error;
1119
1120 if (datalen > 0)
1121 memcpy(data, adp->data, datalen);
1122 return 0;
1123 }
1124
1125 /*
1126 * Initialize the device.
1127 */
1128 int
1129 siop_init(int bus, int dev, int func)
1130 {
1131 struct siop_adapter tmp;
1132 struct siop_xfer *xfer;
1133 struct scsipi_generic *cmd;
1134 struct scsi_request_sense *sense;
1135 uint32_t reg;
1136 u_long addr;
1137 uint32_t *script;
1138 int slot, id, i;
1139 void *scriptaddr;
1140 u_char *data;
1141 const int clock_div = 3; /* 53c810 */
1142
1143 slot = PCISlotnum(bus, dev, func);
1144 if (slot == -1)
1145 return ENOENT;
1146
1147 addr = PCIAddress(slot, 1, PCI_MAPREG_TYPE_MEM);
1148 if (addr == 0xffffffff)
1149 return EINVAL;
1150 enablePCI(slot, 0, 1, 1);
1151
1152 script = ALLOC(uint32_t, SIOP_SCRIPT_SIZE);
1153 if (script == NULL)
1154 return ENOMEM;
1155 scriptaddr = (void *)local_to_PCI((u_long)script);
1156 cmd = ALLOC(struct scsipi_generic, SIOP_SCSI_COMMAND_SIZE);
1157 if (cmd == NULL)
1158 return ENOMEM;
1159 sense = ALLOC(struct scsi_request_sense, SIOP_SCSI_COMMAND_SIZE);
1160 if (sense == NULL)
1161 return ENOMEM;
1162 data = ALLOC(u_char, SIOP_SCSI_DATA_SIZE);
1163 if (data == NULL)
1164 return ENOMEM;
1165 xfer = ALLOC(struct siop_xfer, sizeof(struct siop_xfer));
1166 if (xfer == NULL)
1167 return ENOMEM;
1168 siop_xfer_setup(xfer, scriptaddr);
1169
1170 id = readb(addr + SIOP_SCID) & SCID_ENCID_MASK;
1171
1172 /* reset bus */
1173 reg = readb(addr + SIOP_SCNTL1);
1174 writeb(addr + SIOP_SCNTL1, reg | SCNTL1_RST);
1175 delay(100);
1176 writeb(addr + SIOP_SCNTL1, reg);
1177
1178 /* reset the chip */
1179 writeb(addr + SIOP_ISTAT, ISTAT_SRST);
1180 delay(1000);
1181 writeb(addr + SIOP_ISTAT, 0);
1182
1183 /* init registers */
1184 writeb(addr + SIOP_SCNTL0, SCNTL0_ARB_MASK | SCNTL0_EPC | SCNTL0_AAP);
1185 writeb(addr + SIOP_SCNTL1, 0);
1186 writeb(addr + SIOP_SCNTL3, clock_div);
1187 writeb(addr + SIOP_SXFER, 0);
1188 writeb(addr + SIOP_DIEN, 0xff);
1189 writeb(addr + SIOP_SIEN0, 0xff & ~(SIEN0_CMP | SIEN0_SEL | SIEN0_RSL));
1190 writeb(addr + SIOP_SIEN1, 0xff & ~(SIEN1_HTH | SIEN1_GEN));
1191 writeb(addr + SIOP_STEST2, 0);
1192 writeb(addr + SIOP_STEST3, STEST3_TE);
1193 writeb(addr + SIOP_STIME0, (0xb << STIME0_SEL_SHIFT));
1194 writeb(addr + SIOP_SCID, id | SCID_RRE);
1195 writeb(addr + SIOP_RESPID0, 1 << id);
1196 writeb(addr + SIOP_DCNTL, DCNTL_COM);
1197
1198 siop_pci_reset(addr);
1199
1200 /* copy and patch the script */
1201 for (i = 0; i < __arraycount(siop_script); i++)
1202 script[i] = htoc32(siop_script[i]);
1203 for (i = 0; i < __arraycount(E_abs_msgin_Used); i++)
1204 script[E_abs_msgin_Used[i]] =
1205 htoc32(scriptaddr + Ent_msgin_space);
1206
1207 /* start script */
1208 _wbinv((u_long)script, SIOP_SCRIPT_SIZE);
1209 writel(addr + SIOP_DSP, (int)scriptaddr + Ent_reselect);
1210
1211 memset(&tmp, 0, sizeof(tmp));
1212 tmp.id = id;
1213 tmp.clock_div = clock_div;
1214 tmp.addr = addr;
1215 tmp.script = script;
1216 tmp.xfer = xfer;
1217 tmp.cmd = cmd;
1218 tmp.sense = sense;
1219 tmp.data = data;
1220 tmp.currschedslot = 0;
1221 tmp.sel_t = -1;
1222
1223 if (scsi_probe(&tmp) == 0) {
1224 adapt.addr = 0xffffffff;
1225 return ENXIO;
1226 }
1227 adapt = tmp;
1228 return 0;
1229 }
1230