siop.c revision 1.1 1 /* $NetBSD: siop.c,v 1.1 2000/04/21 17:56:58 bouyer Exp $ */
2
3 /*
4 * Copyright (c) 2000 Manuel Bouyer.
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 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by the University of
17 * California, Berkeley and its contributors.
18 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 */
35
36 /* SYM53c7/8xx PCI-SCSI I/O Processors driver */
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/device.h>
41 #include <sys/malloc.h>
42 #include <sys/buf.h>
43 #include <sys/kernel.h>
44
45 #include <machine/endian.h>
46 #include <machine/bus.h>
47
48 #include <vm/vm.h>
49 #include <vm/vm_param.h>
50 #include <vm/vm_kern.h>
51
52 #include <dev/microcode/siop/siop.out>
53
54 #include <dev/scsipi/scsi_all.h>
55 #include <dev/scsipi/scsi_message.h>
56 #include <dev/scsipi/scsipi_all.h>
57
58 #include <dev/scsipi/scsiconf.h>
59
60 #include <dev/ic/siopreg.h>
61 #include <dev/ic/siopvar.h>
62
63 #ifndef SIOP_DEFAULT_TARGET
64 #define SIOP_DEFAULT_TARGET 7
65 #endif
66
67 #define MEM_SIZE 8192
68 #define SCRIPT_OFF 4096
69
70 /* tables used by SCRIPT */
71 typedef struct scr_table {
72 u_int32_t count;
73 u_int32_t addr;
74 } scr_table_t ;
75
76 /* Number of scatter/gather entries */
77 #define SIOP_NSG (MAXPHYS/NBPG + 1)
78
79 /*
80 * This structure interfaces the SCRIPT with the driver; it describes a full
81 * transfert. It lives in the same chunk of DMA-safe memory as the script.
82 */
83 struct siop_xfer {
84 u_int8_t msg_out; /* 0 */
85 u_int8_t msg_in; /* 1 */
86 u_int8_t status; /* 2 */
87 u_int8_t pad2; /* 3 */
88 u_int32_t id; /* 4 */
89 u_int32_t pad1; /* 8 */
90 scr_table_t t_msgin; /* 12 */
91 scr_table_t t_msgout; /* 20 */
92 scr_table_t cmd; /* 28 */
93 scr_table_t t_status; /* 36 */
94 scr_table_t data[SIOP_NSG]; /* 44 */
95 };
96
97 /*
98 * This decribes a command handled by the SCSI controller
99 * These are chained in either a free list or a active list
100 * We have one queue per target + (one at the adapter's target for probe)
101 */
102 struct siop_cmd {
103 TAILQ_ENTRY (siop_cmd) next;
104 struct siop_softc *siop_sc; /* pointer to adapter */
105 struct scsipi_xfer *xs; /* xfer from the upper level */
106 struct siop_xfer *siop_table; /* tables dealing with this xfer */
107 bus_dmamap_t dmamap_cmd;
108 bus_dmamap_t dmamap_data;
109 struct scsipi_sense rs_cmd; /* request sense command buffer */
110 u_int16_t status;
111 u_int16_t flags;
112 };
113
114 /* status defs */
115 #define CMDST_FREE 0 /* cmd slot is free */
116 #define CMDST_READY 1 /* cmd slot is waiting for processing */
117 #define CMDST_ACTIVE 2 /* cmd slot is being processed */
118 #define CMDST_SENSE 3 /* cmd slot is being requesting sense */
119 #define CMDST_SENSE_DONE 4 /* request sense done */
120 #define CMDST_DONE 5 /* cmd slot has been processed */
121 /* flags defs */
122 #define CMDFL_TIMEOUT 0x0001 /* cmd timed out */
123
124 /* initial number of cmd descriptors */
125 #define SIOP_NCMD 10
126
127 void siop_reset __P((struct siop_softc *));
128 void siop_start __P((struct siop_softc *));
129 void siop_timeout __P((void *));
130 void siop_minphys __P((struct buf *));
131 int siop_scsicmd __P((struct scsipi_xfer *));
132 void siop_sdp __P((struct siop_cmd *));
133 void siop_ssg __P((struct siop_cmd *));
134
135 struct scsipi_adapter siop_adapter = {
136 0,
137 siop_scsicmd,
138 siop_minphys,
139 NULL,
140 };
141
142 struct scsipi_device siop_dev = {
143 NULL,
144 NULL,
145 NULL,
146 NULL,
147 };
148
149 void
150 siop_attach(sc)
151 struct siop_softc *sc;
152 {
153 int error, i;
154 bus_dma_segment_t seg;
155 int rseg;
156 struct siop_cmd *cmds;
157
158 /*
159 * Allocate DMA-safe memory for the script itself and internal
160 * variables and map it.
161 */
162 error = bus_dmamem_alloc(sc->sc_dmat, MEM_SIZE,
163 NBPG, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT);
164 if (error) {
165 printf("%s: unable to allocate script DMA memory, error = %d\n",
166 sc->sc_dev.dv_xname, error);
167 return;
168 }
169 error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, MEM_SIZE,
170 (caddr_t *)&sc->sc_script, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
171 if (error) {
172 printf("%s: unable to map script DMA memory, error = %d\n",
173 sc->sc_dev.dv_xname, error);
174 return;
175 }
176 error = bus_dmamap_create(sc->sc_dmat, MEM_SIZE, 1,
177 MEM_SIZE, 0, BUS_DMA_NOWAIT, &sc->sc_scriptdma);
178 if (error) {
179 printf("%s: unable to create script DMA map, error = %d\n",
180 sc->sc_dev.dv_xname, error);
181 return;
182 }
183 error = bus_dmamap_load(sc->sc_dmat, sc->sc_scriptdma, sc->sc_script,
184 MEM_SIZE, NULL, BUS_DMA_NOWAIT);
185 if (error) {
186 printf("%s: unable to load script DMA map, error = %d\n",
187 sc->sc_dev.dv_xname, error);
188 return;
189 }
190 TAILQ_INIT(&sc->free_list);
191 for (i = 0; i < 16; i++)
192 TAILQ_INIT(&sc->active_list[i]);
193 /* allocate cmd list */
194 cmds = malloc(sizeof(struct siop_cmd) * SIOP_NCMD, M_DEVBUF, M_NOWAIT);
195 if (cmds == NULL) {
196 printf("%s: can't allocate memory for command descriptors\n",
197 sc->sc_dev.dv_xname);
198 return;
199 }
200 for (i = 0; i < SIOP_NCMD; i++) {
201 error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, SIOP_NSG,
202 MAXPHYS, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
203 &cmds[i].dmamap_data);
204 if (error) {
205 printf("%s: unable to create data DMA map for cbd %d\n",
206 sc->sc_dev.dv_xname, error);
207 return;
208 }
209 error = bus_dmamap_create(sc->sc_dmat,
210 sizeof(struct scsipi_generic), 1,
211 sizeof(struct scsipi_generic), 0,
212 BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
213 &cmds[i].dmamap_cmd);
214 if (error) {
215 printf("%s: unable to create cmd DMA map for cbd %d\n",
216 sc->sc_dev.dv_xname, error);
217 return;
218 }
219 cmds[i].siop_sc = sc;
220 cmds[i].siop_table = &((struct siop_xfer *)sc->sc_script)[i];
221 cmds[i].status = CMDST_FREE;
222 cmds[i].siop_table->t_msgout.count= htole32(1);
223 cmds[i].siop_table->t_msgout.addr =
224 htole32(sc->sc_scriptdma->dm_segs[0].ds_addr +
225 i * sizeof(struct siop_xfer));
226 cmds[i].siop_table->t_msgin.count= htole32(1);
227 cmds[i].siop_table->t_msgin.addr =
228 htole32(htole32(cmds[i].siop_table->t_msgout.addr) + 1);
229 cmds[i].siop_table->t_status.count= htole32(1);
230 cmds[i].siop_table->t_status.addr =
231 htole32(htole32(cmds[i].siop_table->t_msgin.addr) + 1);
232 TAILQ_INSERT_TAIL(&sc->free_list, &cmds[i], next);
233 printf("tables[%d]: out=0x%x in=0x%x status=0x%x\n", i,
234 cmds[i].siop_table->t_msgin.addr,
235 cmds[i].siop_table->t_msgout.addr,
236 cmds[i].siop_table->t_status.addr);
237 }
238 #ifdef DEBUG
239 printf("%s: script size = %d, PHY addr=0x%x, VIRT=%p\n",
240 sc->sc_dev.dv_xname, sizeof(siop_script),
241 (u_int)sc->sc_scriptdma->dm_segs[0].ds_addr, sc->sc_script);
242 #endif
243
244 sc->sc_link.adapter_softc = sc;
245 sc->sc_link.openings = 1;
246 sc->sc_link.scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE;
247 sc->sc_link.scsipi_scsi.max_target =
248 (sc->features & SF_BUS_WIDE) ? 15 : 7;
249 sc->sc_link.scsipi_scsi.max_lun = 7;
250 sc->sc_link.scsipi_scsi.adapter_target = bus_space_read_1(sc->sc_rt,
251 sc->sc_rh, SIOP_SCID);
252 if (sc->sc_link.scsipi_scsi.adapter_target >
253 sc->sc_link.scsipi_scsi.max_target)
254 sc->sc_link.scsipi_scsi.adapter_target = SIOP_DEFAULT_TARGET;
255 sc->sc_link.type = BUS_SCSI;
256 sc->sc_link.adapter = &siop_adapter;
257 sc->sc_link.device = &siop_dev;
258 sc->sc_link.flags = 0;
259
260 siop_reset(sc);
261
262 config_found((struct device*)sc, &sc->sc_link, scsiprint);
263 }
264
265 void
266 siop_reset(sc)
267 struct siop_softc *sc;
268 {
269 /* reset the chip */
270 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SRST);
271 delay(1000);
272 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, 0);
273
274 /* copy and patch the script */
275 memcpy(&sc->sc_script[SCRIPT_OFF/4], siop_script, sizeof(siop_script));
276
277 /* init registers */
278 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL0,
279 SCNTL0_ARB_MASK | SCNTL0_EPC | SCNTL0_AAP);
280 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, 0);
281 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, 0x3);
282 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DIEN, 0xff);
283 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN0,
284 0xff & ~(SIEN0_CMP | SIEN0_SEL | SIEN0_RSL));
285 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN1,
286 0xff & ~(SIEN1_HTH | SIEN1_GEN));
287 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, STEST2_EXT);
288 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, STEST3_TE);
289 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STIME0,
290 (0xb << STIME0_SEL_SHIFT));
291 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCID,
292 sc->sc_link.scsipi_scsi.adapter_target | SCID_RRE);
293 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_RESPID0,
294 1 << sc->sc_link.scsipi_scsi.adapter_target);
295 }
296
297 #if 0
298 #define CALL_SCRIPT(ent) do {\
299 printf ("start script DSA 0x%lx DSP 0x%lx\n", \
300 htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + \
301 (((caddr_t)siop_cmd->siop_table) - ((caddr_t)sc->sc_script))),\
302 htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + SCRIPT_OFF + ent)); \
303 bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSA, \
304 htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + \
305 (((caddr_t)siop_cmd->siop_table) - ((caddr_t)sc->sc_script)))); \
306 bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + SCRIPT_OFF + ent)); \
307 } while (0)
308 #else
309 #define CALL_SCRIPT(ent) do {\
310 bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSA, \
311 htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + \
312 (((caddr_t)siop_cmd->siop_table) - ((caddr_t)sc->sc_script)))); \
313 bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + SCRIPT_OFF + ent)); \
314 } while (0)
315 #endif
316
317 int
318 siop_intr(v)
319 void *v;
320 {
321 struct siop_softc *sc = v;
322 struct siop_cmd *siop_cmd;
323 struct scsipi_xfer *xs;
324 u_int8_t istat, sist0, sist1, sstat1, dstat, scntl1;
325 u_int32_t irqcode;
326 int need_reset = 0;
327 int offset;
328
329 istat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT);
330 if (istat & ISTAT_INTF) {
331 printf("INTRF\n");
332 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_INTF);
333 }
334 if (istat & ISTAT_DIP) {
335 u_int32_t *p;
336 dstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DSTAT);
337 if (dstat & ~(DSTAT_SIR | DSTAT_DFE)) {
338 printf("DMA IRQ:");
339 if (dstat & DSTAT_IID)
340 printf(" Illegal instruction");
341 if (dstat & DSTAT_SSI)
342 printf(" single step");
343 if (dstat & DSTAT_ABRT)
344 printf(" abort");
345 if (dstat & DSTAT_BF)
346 printf(" bus fault");
347 if (dstat & DSTAT_MDPE)
348 printf(" parity");
349 if (dstat & DSTAT_DFE)
350 printf(" dma fifo empty");
351 printf(", DSP=0x%x DSA=0x%x: ",
352 bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP),
353 bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA));
354 p = &sc->sc_script[SCRIPT_OFF/4] +
355 (bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
356 (sc->sc_scriptdma->dm_segs[0].ds_addr + SCRIPT_OFF)-8) / 4;
357 printf("0x%x 0x%x 0x%x 0x%x\n", p[0], p[1], p[2], p[3]);
358 if ((siop_cmd = sc->active_list[sc->current_target].tqh_first))
359 printf("last msg_in=0x%x status=0x%x\n",
360 siop_cmd->siop_table->msg_in,
361 siop_cmd->siop_table->status);
362 need_reset = 1;
363 }
364 }
365 if (istat & ISTAT_SIP) {
366 if (istat & ISTAT_DIP)
367 delay(1);
368 sist0 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST0);
369 delay(1);
370 sist1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST1);
371 sstat1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1);
372 #if 0
373 printf("scsi interrupt, sist0=0x%x sist1=0x%x sstat1=0x%x "
374 "DSA=0x%x DSP=0x%x\n", sist0, sist1,
375 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1),
376 bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA),
377 bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP));
378 #endif
379 siop_cmd = sc->active_list[sc->current_target].tqh_first;
380 if (siop_cmd)
381 xs = siop_cmd->xs;
382 if (sist0 & SIST0_RST) {
383 /* scsi bus reset. reset the chip and restart
384 * the queue.
385 */
386 printf("%s: scsi bus reset\n", sc->sc_dev.dv_xname);
387 /* if we had a command running handle it */
388 if (siop_cmd) {
389 xs = siop_cmd->xs;
390 if (siop_cmd->status == CMDST_ACTIVE ||
391 siop_cmd->status == CMDST_SENSE)
392 xs->error =
393 (siop_cmd->flags & CMDFL_TIMEOUT) ?
394 XS_TIMEOUT : XS_RESET;
395 }
396 siop_reset(sc);
397 if (siop_cmd)
398 goto end;
399 siop_start(sc);
400 return 1;
401 }
402 if (sist0 & SIST0_SGE) {
403 if (siop_cmd)
404 scsi_print_addr(xs->sc_link);
405 else
406 printf("%s:", sc->sc_dev.dv_xname);
407 printf("scsi gross error\n");
408 goto reset;
409 }
410 if ((sist0 & SIST0_MA) && need_reset == 0) {
411 if (siop_cmd) {
412 switch (sstat1 & SSTAT1_PHASE_MASK) {
413 case SSTAT1_PHASE_STATUS:
414 /*
415 * previous phase may be aborted for any reason
416 * ( for example, the target has less data to
417 * transfer than requested). Just go to status
418 * and the command should terminate.
419 */
420 CALL_SCRIPT(Ent_status);
421 return 1;
422 case SSTAT1_PHASE_MSGIN:
423 /*
424 * target may be ready to disconnect
425 * Save data pointers just in case.
426 */
427 siop_sdp(siop_cmd);
428 CALL_SCRIPT(Ent_msgin);
429 return 1;
430 }
431 printf("%s: unexpected phase mismatch %d\n",
432 sc->sc_dev.dv_xname,
433 sstat1 & SSTAT1_PHASE_MASK);
434 } else {
435 printf("%s: phase mismatch without command\n",
436 sc->sc_dev.dv_xname);
437 }
438 need_reset = 1;
439 }
440 if (sist0 & SIST0_PAR) {
441 /* parity error, reset */
442 if (siop_cmd)
443 scsi_print_addr(xs->sc_link);
444 else
445 printf("%s:", sc->sc_dev.dv_xname);
446 printf("parity error\n");
447 need_reset = 1;
448 }
449 if ((sist1 & SIST1_STO) && need_reset == 0) {
450 /* selection time out, assume there's no device here */
451 if (siop_cmd) {
452 siop_cmd->status = CMDST_DONE;
453 xs->error = XS_SELTIMEOUT;
454 goto end;
455 } else {
456 printf("%s: selection timeout without "
457 "command\n", sc->sc_dev.dv_xname);
458 need_reset = 1;
459 }
460 }
461 if (sist0 & SIST0_UDC) {
462 /*
463 * unexpected disconnect. Usually the target signals
464 * a fatal condition this way. Attempt to get sense.
465 */
466 if (siop_cmd)
467 goto check_sense;
468 printf("%s: unexpected disconnect without "
469 "command\n", sc->sc_dev.dv_xname);
470 need_reset = 1;
471 }
472 /* Else it's an unhandled exeption (for now). */
473 printf("%s: unhandled scsi interrupt, sist0=0x%x sist1=0x%x "
474 "sstat1=0x%x DSA=0x%x DSP=0x%x\n", sc->sc_dev.dv_xname,
475 sist0, sist1,
476 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1),
477 bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA),
478 bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP));
479 if (siop_cmd) {
480 siop_cmd->status = CMDST_DONE;
481 xs->error = XS_SELTIMEOUT;
482 goto end;
483 }
484 need_reset = 1;
485 }
486 if (need_reset) {
487 reset:
488 /* fatal error, reset the bus */
489 scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1);
490 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1,
491 scntl1 | SCNTL1_RST);
492 /* minimum 25 us, more time won't hurt */
493 delay(100);
494 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);
495 return 1;
496 }
497
498
499 siop_cmd = sc->active_list[sc->current_target].tqh_first;
500 if (siop_cmd == NULL) {
501 printf("Aie, no command !\n");
502 return(1);
503 }
504 xs = siop_cmd->xs;
505 if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) { /* script interrupt */
506 irqcode = bus_space_read_4(sc->sc_rt, sc->sc_rh,
507 SIOP_DSPS);
508 switch(irqcode) {
509 case A_int_err:
510 printf("error\n");
511 xs->error = XS_SELTIMEOUT;
512 goto end;
513 case A_int_msgin:
514 scsi_print_addr(xs->sc_link);
515 printf("unhandled message %d\n",
516 siop_cmd->siop_table->msg_in);
517 xs->error = XS_DRIVER_STUFFUP;
518 goto end;
519 case A_int_resel: /* reselected */
520 if ((siop_cmd->siop_table->msg_in & 0x80) == 0) {
521 printf("%s: reselect without identify (%d)\n",
522 sc->sc_dev.dv_xname,
523 siop_cmd->siop_table->msg_in);
524 goto reset;
525 }
526 sc->current_target = bus_space_read_1(sc->sc_rt,
527 sc->sc_rh, SIOP_SCRATCHA);
528 if ((sc->current_target & 0x80) == 0) {
529 printf("reselect without id (%d)\n",
530 sc->current_target);
531 goto reset;
532 }
533 sc->current_target &= 0x0f;
534 #ifdef DEBUG_DR
535 printf("reselected by target %d lun %d\n",
536 sc->current_target,
537 siop_cmd->siop_table->msg_in & 0x07);
538 #endif
539 siop_cmd =
540 sc->active_list[sc->current_target].tqh_first;
541 if (siop_cmd == NULL) {
542 printf("%s: reselected without cmd\n",
543 sc->sc_dev.dv_xname);
544 goto reset;
545 }
546 bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSA,
547 htole32(sc->sc_scriptdma->dm_segs[0].ds_addr +
548 (((caddr_t)siop_cmd->siop_table) -
549 ((caddr_t)sc->sc_script))));
550 CALL_SCRIPT(Ent_reselected);
551 return 1;
552 case A_int_disc:
553 offset = bus_space_read_1(sc->sc_rt, sc->sc_rh,
554 SIOP_SCRATCHA + 1);
555 #ifdef DEBUG_DR
556 printf("disconnect offset %d\n", offset);
557 #endif
558 if (offset > SIOP_NSG) {
559 printf("%s: bad offset for disconnect (%d)\n",
560 sc->sc_dev.dv_xname, offset);
561 goto reset;
562 }
563 /*
564 * offset == SIOP_NSG may be a valid condition if
565 * we get a sdp when the xfer is done.
566 * Don't call memmove in this case.
567 */
568 if (offset < SIOP_NSG) {
569 memmove(&siop_cmd->siop_table->data[0],
570 &siop_cmd->siop_table->data[offset],
571 (SIOP_NSG - offset) * sizeof(scr_table_t));
572 }
573 CALL_SCRIPT(Ent_reselect);
574 return 1;
575 case A_int_resfail:
576 printf("reselect failed\n");
577 CALL_SCRIPT(Ent_reselect);
578 return 1;
579 case A_int_done:
580 #if 0
581 printf("done, taget id 0x%x last msg in=0x%x "
582 "status=0x%x\n",
583 siop_cmd->siop_table->id,
584 siop_cmd->siop_table->msg_in,
585 siop_cmd->siop_table->status);
586 #endif
587 if (siop_cmd->status == CMDST_SENSE)
588 siop_cmd->status = CMDST_SENSE_DONE;
589 else
590 siop_cmd->status = CMDST_DONE;
591 switch(siop_cmd->siop_table->status) {
592 case SCSI_OK:
593 xs->error = (siop_cmd->status == CMDST_DONE) ?
594 XS_NOERROR : XS_SENSE;
595 break;
596 case SCSI_BUSY:
597 xs->error = XS_BUSY;
598 break;
599 case SCSI_CHECK:
600 check_sense:
601 if (siop_cmd->status == CMDST_SENSE_DONE) {
602 /* request sense on a request sense ? */ printf("request sense failed\n");
603 xs->error = XS_DRIVER_STUFFUP;
604 } else {
605 siop_cmd->status = CMDST_SENSE;
606 }
607 break;
608 case 0xff:
609 /*
610 * the status byte was not updated, cmd was
611 * aborted
612 */
613 xs->error = XS_SELTIMEOUT;
614 default:
615 xs->error = XS_DRIVER_STUFFUP;
616 }
617 goto end;
618 default:
619 printf("unknown irqcode %x\n", irqcode);
620 xs->error = XS_SELTIMEOUT;
621 goto end;
622 }
623 return 1;
624 }
625 siop_cmd->status = CMDST_DONE;
626 xs->error = XS_BUSY;
627 goto end;
628 end:
629 if (siop_cmd->status != CMDST_SENSE_DONE &&
630 xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
631 bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
632 siop_cmd->dmamap_data->dm_mapsize,
633 (xs->xs_control & XS_CTL_DATA_IN) ?
634 BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
635 bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_data);
636 }
637 bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
638 if (siop_cmd->status == CMDST_SENSE) {
639 /* issue a request sense for this target */
640 int error, i;
641 siop_cmd->rs_cmd.opcode = REQUEST_SENSE;
642 siop_cmd->rs_cmd.byte2 = xs->sc_link->scsipi_scsi.lun << 5;
643 siop_cmd->rs_cmd.unused[0] = siop_cmd->rs_cmd.unused[1] = 0;
644 siop_cmd->rs_cmd.length = sizeof(struct scsipi_sense_data);
645 siop_cmd->rs_cmd.control = 0;
646 siop_cmd->siop_table->status = 0xff; /* set invalid status */
647 error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_cmd,
648 &siop_cmd->rs_cmd, sizeof(struct scsipi_sense),
649 NULL, BUS_DMA_NOWAIT);
650 if (error) {
651 printf("%s: unable to load cmd DMA map: %d",
652 sc->sc_dev.dv_xname, error);
653 xs->error = XS_DRIVER_STUFFUP;
654 goto out;
655 }
656 siop_cmd->siop_table->cmd.count =
657 htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_len);
658 siop_cmd->siop_table->cmd.addr =
659 htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_addr);
660 error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_data,
661 &xs->sense.scsi_sense, sizeof(struct scsipi_sense_data),
662 NULL, BUS_DMA_NOWAIT);
663 if (error) {
664 printf("%s: unable to load sense DMA map: %d",
665 sc->sc_dev.dv_xname, error);
666 xs->error = XS_DRIVER_STUFFUP;
667 bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
668 goto out;
669 }
670 for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) {
671 siop_cmd->siop_table->data[i].count =
672 htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len);
673 siop_cmd->siop_table->data[i].addr =
674 htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr);
675 }
676 bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
677 siop_cmd->dmamap_data->dm_mapsize, BUS_DMASYNC_PREREAD);
678 bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_cmd, 0,
679 siop_cmd->dmamap_cmd->dm_mapsize, BUS_DMASYNC_PREWRITE);
680 bus_dmamap_sync(sc->sc_dmat, sc->sc_scriptdma, 0,
681 sc->sc_scriptdma->dm_mapsize, BUS_DMASYNC_PREWRITE);
682 siop_start(sc);
683 return(1);
684 } else if (siop_cmd->status == CMDST_SENSE_DONE) {
685 bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
686 siop_cmd->dmamap_data->dm_mapsize, BUS_DMASYNC_POSTREAD);
687 bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_data);
688 }
689 out:
690 callout_stop(&siop_cmd->xs->xs_callout);
691 TAILQ_REMOVE(&sc->active_list[sc->current_target], siop_cmd, next);
692 siop_cmd->status = CMDST_FREE;
693 TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next);
694 xs->xs_status |= XS_STS_DONE;
695 xs->resid = 0;
696 scsipi_done (xs);
697 /* restart any pending cmd */
698 siop_start(sc);
699 return 1;
700 }
701
702 void
703 siop_minphys(bp)
704 struct buf *bp;
705 {
706 minphys(bp);
707 }
708
709 int
710 siop_scsicmd(xs)
711 struct scsipi_xfer *xs;
712 {
713 struct siop_softc *sc = (struct siop_softc *)xs->sc_link->adapter_softc;
714 struct siop_cmd *siop_cmd;
715 int s, error, i;
716 u_int32_t id;
717
718 s = splbio();
719 #if 0
720 printf("starting cmd for %d:%d\n", xs->sc_link->scsipi_scsi.target,xs->sc_link->scsipi_scsi.lun);
721 #endif
722 siop_cmd = sc->free_list.tqh_first;
723 if (siop_cmd) {
724 TAILQ_REMOVE(&sc->free_list, siop_cmd, next);
725 }
726 splx(s);
727 if (siop_cmd == NULL) {
728 xs->error = XS_DRIVER_STUFFUP;
729 return(TRY_AGAIN_LATER);
730 }
731 #ifdef DIAGNOSTIC
732 if (siop_cmd->status != CMDST_FREE)
733 panic("siop_scsicmd: new cmd not free");
734 #endif
735 siop_cmd->xs = xs;
736 id = 0x3 << 24; /* scntl3 */
737 id |= xs->sc_link->scsipi_scsi.target << 16; /* id */
738 id |= 0xe0 << 8; /* scxfer */
739 siop_cmd->siop_table->id = htole32(id);
740 siop_cmd->siop_table->msg_out =
741 MSG_IDENTIFY(xs->sc_link->scsipi_scsi.lun, 1);
742 siop_cmd->siop_table->status = 0xff; /* set invalid status */
743
744 /* load the DMA maps */
745 error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_cmd,
746 xs->cmd, xs->cmdlen, NULL, BUS_DMA_NOWAIT);
747 if (error) {
748 printf("%s: unable to load cmd DMA map: %d",
749 sc->sc_dev.dv_xname, error);
750 xs->error = XS_DRIVER_STUFFUP;
751 return(TRY_AGAIN_LATER);
752 }
753 siop_cmd->siop_table->cmd.count =
754 htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_len);
755 siop_cmd->siop_table->cmd.addr =
756 htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_addr);
757 if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
758 error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_data,
759 xs->data, xs->datalen, NULL, BUS_DMA_NOWAIT);
760 if (error) {
761 printf("%s: unable to load cmd DMA map: %d",
762 sc->sc_dev.dv_xname, error);
763 xs->error = XS_DRIVER_STUFFUP;
764 return(TRY_AGAIN_LATER);
765 bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
766 }
767 for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) {
768 siop_cmd->siop_table->data[i].count =
769 htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len);
770 siop_cmd->siop_table->data[i].addr =
771 htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr);
772 }
773 bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
774 siop_cmd->dmamap_data->dm_mapsize,
775 (xs->xs_control & XS_CTL_DATA_IN) ?
776 BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
777 }
778 bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_cmd, 0,
779 siop_cmd->dmamap_cmd->dm_mapsize, BUS_DMASYNC_PREWRITE);
780 bus_dmamap_sync(sc->sc_dmat, sc->sc_scriptdma, 0,
781 sc->sc_scriptdma->dm_mapsize, BUS_DMASYNC_PREWRITE);
782
783 siop_cmd->status = CMDST_READY;
784 s = splbio();
785 TAILQ_INSERT_TAIL(&sc->active_list[xs->sc_link->scsipi_scsi.target],
786 siop_cmd, next);
787 if ((sc->sc_flags & SC_CTRL_ACTIVE) == 0) {
788 siop_start(sc);
789 }
790 splx(s);
791 return (SUCCESSFULLY_QUEUED);
792 }
793
794 void
795 siop_start(sc)
796 struct siop_softc *sc;
797 {
798 struct siop_cmd *siop_cmd;
799 int timeout;
800 int i;
801
802 for (i = 0; i < 16; i++) {
803 siop_cmd = sc->active_list[i].tqh_first;
804 if (siop_cmd) {
805 sc->current_target = i;
806 break;
807 }
808 }
809 if (siop_cmd == NULL) {
810 sc->sc_flags &= ~SC_CTRL_ACTIVE;
811 return;
812 }
813
814 sc->sc_flags |= SC_CTRL_ACTIVE;
815 if (siop_cmd->status == CMDST_READY &&
816 (siop_cmd->xs->xs_control & XS_CTL_POLL) == 0) {
817 /* start exire timer */
818 timeout = siop_cmd->xs->timeout * hz / 1000;
819 if (timeout == 0)
820 timeout = 1; /* at last one tick */
821 callout_reset(&siop_cmd->xs->xs_callout, timeout,
822 siop_timeout, siop_cmd);
823 }
824 /* load DSA */
825 bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSA,
826 htole32(sc->sc_scriptdma->dm_segs[0].ds_addr +
827 (((caddr_t)siop_cmd->siop_table) - ((caddr_t)sc->sc_script))));
828 /* mark command as active (if not reqsense) and start script */
829 if (siop_cmd->status == CMDST_READY)
830 siop_cmd->status = CMDST_ACTIVE;
831 #if 0
832 printf("starting script, DSA 0x%lx\n",
833 htole32(sc->sc_scriptdma->dm_segs[0].ds_addr +
834 (((caddr_t)siop_cmd->siop_table) - ((caddr_t)sc->sc_script))));
835 #endif
836 bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
837 htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + SCRIPT_OFF + Ent_select));
838 /* now wait for IRQ */
839 }
840
841 void
842 siop_timeout(v)
843 void *v;
844 {
845 struct siop_cmd *siop_cmd = v;
846 struct siop_softc *sc = siop_cmd->siop_sc;
847 int s;
848 u_int8_t scntl1;
849
850 scsi_print_addr(siop_cmd->xs->sc_link);
851 printf("command timeout\n");
852
853 s = splbio();
854 /* reset the scsi bus */
855 scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1);
856 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1,
857 scntl1 | SCNTL1_RST);
858 /* minimum 25 us, more time won't hurt */
859 delay(100);
860 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);
861
862 /* desactivate callout */
863 callout_stop(&siop_cmd->xs->xs_callout);
864 /* mark command has being timed out; siop_intr will handle it */
865 /*
866 * mark command has being timed out and just return;
867 * the bus reset will generate an interrupt,
868 * it will be handled in siop_intr()
869 */
870 siop_cmd->flags |= CMDFL_TIMEOUT;
871 splx(s);
872 return;
873
874 }
875
876 void
877 siop_sdp(siop_cmd)
878 struct siop_cmd *siop_cmd;
879 {
880 /* save data pointer. Handle async only for now */
881 int offset, dbc, sstat;
882 struct siop_softc *sc = siop_cmd->siop_sc;
883 scr_table_t *table; /* table to patch */
884
885 if ((siop_cmd->xs->xs_control & (XS_CTL_DATA_OUT | XS_CTL_DATA_IN))
886 == 0)
887 return; /* no data pointers to save */
888 offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA + 1);
889 if (offset >= SIOP_NSG) {
890 printf("%s: bad offset in siop_sdp (%d)\n",
891 sc->sc_dev.dv_xname, offset);
892 return;
893 }
894 table = &siop_cmd->siop_table->data[offset];
895 #ifdef DEBUG_DR
896 printf("sdp: offset %d count=%d addr=0x%x ", offset,
897 table->count, table->addr);
898 #endif
899 dbc = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DBC) & 0x00ffffff;
900 if (siop_cmd->xs->xs_control & XS_CTL_DATA_OUT) {
901 /* need to account stale data in FIFO */
902 /* XXX check for large fifo */
903 dbc += (bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DFIFO) -
904 (dbc & 0x7f)) & 0x7f;
905 sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT0);
906 if (sstat & SSTAT0_OLF)
907 dbc++;
908 if (sstat & SSTAT0_ORF)
909 dbc++;
910 /* XXX check sstat1 for wide adapters */
911 /* Flush the FIFO */
912 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
913 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) |
914 CTEST3_CLF);
915 }
916 table->addr =
917 htole32(htole32(table->addr) + htole32(table->count) - dbc);
918 table->count = htole32(dbc);
919 #ifdef DEBUG_DR
920 printf("now count=%d addr=0x%x\n", table->count, table->addr);
921 #endif
922 }
923