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