1 /* $OpenBSD: siop_common.c,v 1.19 2004/01/15 17:51:42 miod Exp $ */
2 /* $NetBSD: siop_common.c,v 1.31 2002/09/27 15:37:18 provos Exp $ */
3
4 /*
5 * Copyright (c) 2000, 2002 Manuel Bouyer.
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 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Manuel Bouyer.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
34 /* SYM53c7/8xx PCI-SCSI I/O Processors driver */
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/device.h>
39 #include <sys/malloc.h>
40 #include <sys/buf.h>
41 #include <sys/kernel.h>
42 #include <sys/scsiio.h>
43
44 #include <machine/endian.h>
45 #include <machine/bus.h>
46
47 #include <scsi/scsi_all.h>
48 #include <scsi/scsi_message.h>
49 #include <scsi/scsiconf.h>
50
51 #include <dev/ic/siopreg.h>
52 #include <dev/ic/siopvar_common.h>
53 #include <dev/ic/siopvar.h>
54
55 #undef DEBUG
56 #undef DEBUG_DR
57 #undef DEBUG_NEG
58
59 int
siop_common_attach(sc)60 siop_common_attach(sc)
61 struct siop_common_softc *sc;
62 {
63 int error, i;
64 bus_dma_segment_t seg;
65 int rseg;
66
67 /*
68 * Allocate DMA-safe memory for the script and map it.
69 */
70 if ((sc->features & SF_CHIP_RAM) == 0) {
71 error = bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE,
72 PAGE_SIZE, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT);
73 if (error) {
74 printf("%s: unable to allocate script DMA memory, "
75 "error = %d\n", sc->sc_dev.dv_xname, error);
76 return error;
77 }
78 error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, PAGE_SIZE,
79 (caddr_t *)&sc->sc_script,
80 BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
81 if (error) {
82 printf("%s: unable to map script DMA memory, "
83 "error = %d\n", sc->sc_dev.dv_xname, error);
84 return error;
85 }
86 error = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1,
87 PAGE_SIZE, 0, BUS_DMA_NOWAIT, &sc->sc_scriptdma);
88 if (error) {
89 printf("%s: unable to create script DMA map, "
90 "error = %d\n", sc->sc_dev.dv_xname, error);
91 return error;
92 }
93 error = bus_dmamap_load(sc->sc_dmat, sc->sc_scriptdma,
94 sc->sc_script, PAGE_SIZE, NULL, BUS_DMA_NOWAIT);
95 if (error) {
96 printf("%s: unable to load script DMA map, "
97 "error = %d\n", sc->sc_dev.dv_xname, error);
98 return error;
99 }
100 sc->sc_scriptaddr =
101 sc->sc_scriptdma->dm_segs[0].ds_addr;
102 sc->ram_size = PAGE_SIZE;
103 }
104
105 /*
106 * sc->sc_link is the template for all device sc_link's
107 * for devices attached to this adapter. It is passed to
108 * the upper layers in config_found().
109 */
110 sc->sc_link.adapter_softc = sc;
111 sc->sc_link.adapter_buswidth =
112 (sc->features & SF_BUS_WIDE) ? 16 : 8;
113 sc->sc_link.adapter_target =
114 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCID);
115 if (sc->sc_link.adapter_target == 0 ||
116 sc->sc_link.adapter_target >=
117 sc->sc_link.adapter_buswidth)
118 sc->sc_link.adapter_target = SIOP_DEFAULT_TARGET;
119
120 for (i = 0; i < 16; i++)
121 sc->targets[i] = NULL;
122
123 /* find min/max sync period for this chip */
124 sc->st_maxsync = 0;
125 sc->dt_maxsync = 0;
126 sc->st_minsync = 255;
127 sc->dt_minsync = 255;
128 for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); i++) {
129 if (sc->clock_period != scf_period[i].clock)
130 continue;
131 if (sc->st_maxsync < scf_period[i].period)
132 sc->st_maxsync = scf_period[i].period;
133 if (sc->st_minsync > scf_period[i].period)
134 sc->st_minsync = scf_period[i].period;
135 }
136 if (sc->st_maxsync == 255 || sc->st_minsync == 0)
137 panic("siop: can't find my sync parameters");
138 for (i = 0; i < sizeof(dt_scf_period) / sizeof(dt_scf_period[0]); i++) {
139 if (sc->clock_period != dt_scf_period[i].clock)
140 continue;
141 if (sc->dt_maxsync < dt_scf_period[i].period)
142 sc->dt_maxsync = dt_scf_period[i].period;
143 if (sc->dt_minsync > dt_scf_period[i].period)
144 sc->dt_minsync = dt_scf_period[i].period;
145 }
146 if (sc->dt_maxsync == 255 || sc->dt_minsync == 0)
147 panic("siop: can't find my sync parameters");
148 return 0;
149 }
150
151 void
siop_common_reset(sc)152 siop_common_reset(sc)
153 struct siop_common_softc *sc;
154 {
155 u_int32_t stest3;
156
157 /* reset the chip */
158 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SRST);
159 delay(1000);
160 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, 0);
161
162 /* init registers */
163 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL0,
164 SCNTL0_ARB_MASK | SCNTL0_EPC | SCNTL0_AAP);
165 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, 0);
166 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, sc->clock_div);
167 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER, 0);
168 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DIEN, 0xff);
169 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN0,
170 0xff & ~(SIEN0_CMP | SIEN0_SEL | SIEN0_RSL));
171 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN1,
172 0xff & ~(SIEN1_HTH | SIEN1_GEN));
173 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, 0);
174 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, STEST3_TE);
175 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STIME0,
176 (0xb << STIME0_SEL_SHIFT));
177 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCID,
178 sc->sc_link.adapter_target | SCID_RRE);
179 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_RESPID0,
180 1 << sc->sc_link.adapter_target);
181 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DCNTL,
182 (sc->features & SF_CHIP_PF) ? DCNTL_COM | DCNTL_PFEN : DCNTL_COM);
183
184 /* enable clock doubler or quadruler if appropriate */
185 if (sc->features & (SF_CHIP_DBLR | SF_CHIP_QUAD)) {
186 stest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3);
187 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1,
188 STEST1_DBLEN);
189 if (sc->features & SF_CHIP_QUAD) {
190 /* wait for PPL to lock */
191 while ((bus_space_read_1(sc->sc_rt, sc->sc_rh,
192 SIOP_STEST4) & STEST4_LOCK) == 0)
193 delay(10);
194 } else {
195 /* data sheet says 20us - more won't hurt */
196 delay(100);
197 }
198 /* halt scsi clock, select doubler/quad, restart clock */
199 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3,
200 stest3 | STEST3_HSC);
201 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1,
202 STEST1_DBLEN | STEST1_DBLSEL);
203 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, stest3);
204 } else {
205 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1, 0);
206 }
207 if (sc->features & SF_CHIP_FIFO)
208 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST5,
209 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST5) |
210 CTEST5_DFS);
211 if (sc->features & SF_CHIP_LED0) {
212 /* Set GPIO0 as output if software LED control is required */
213 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_GPCNTL,
214 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_GPCNTL) & 0xfe);
215 }
216 if (sc->features & SF_BUS_ULTRA3) {
217 /* reset SCNTL4 */
218 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL4, 0);
219 }
220 sc->mode = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST4) &
221 STEST4_MODE_MASK;
222
223 /*
224 * initialise the RAM. Without this we may get scsi gross errors on
225 * the 1010
226 */
227 if (sc->features & SF_CHIP_RAM)
228 bus_space_set_region_4(sc->sc_ramt, sc->sc_ramh,
229 0, 0, sc->ram_size / 4);
230 sc->sc_reset(sc);
231 }
232
233 /* prepare tables before sending a cmd */
234 void
siop_setuptables(siop_cmd)235 siop_setuptables(siop_cmd)
236 struct siop_common_cmd *siop_cmd;
237 {
238 int i;
239 struct siop_common_softc *sc = siop_cmd->siop_sc;
240 struct scsi_xfer *xs = siop_cmd->xs;
241 int target = xs->sc_link->target;
242 int lun = xs->sc_link->lun;
243 int msgoffset = 1;
244 int *targ_flags = &sc->targets[target]->flags;
245 int quirks;
246
247 siop_cmd->siop_tables->id = htole32(sc->targets[target]->id);
248 memset(siop_cmd->siop_tables->msg_out, 0,
249 sizeof(siop_cmd->siop_tables->msg_out));
250 /* request sense doesn't disconnect */
251 if (siop_cmd->status == CMDST_SENSE)
252 siop_cmd->siop_tables->msg_out[0] = MSG_IDENTIFY(lun, 0);
253 else if ((sc->features & SF_CHIP_GEBUG) &&
254 (sc->targets[target]->flags & TARF_ISWIDE) == 0)
255 /*
256 * 1010 bug: it seems that the 1010 has problems with reselect
257 * when not in wide mode (generate false SCSI gross error).
258 * The FreeBSD sym driver has comments about it but their
259 * workaround (disable SCSI gross error reporting) doesn't
260 * work with my adapter. So disable disconnect when not
261 * wide.
262 */
263 siop_cmd->siop_tables->msg_out[0] = MSG_IDENTIFY(lun, 0);
264 else
265 siop_cmd->siop_tables->msg_out[0] = MSG_IDENTIFY(lun, 1);
266 siop_cmd->siop_tables->t_msgout.count= htole32(msgoffset);
267 if (sc->targets[target]->status == TARST_ASYNC) {
268 *targ_flags &= TARF_DT; /* Save TARF_DT 'cuz we don't set it here */
269 quirks = xs->sc_link->quirks;
270
271 #ifndef __hppa__
272 if ((quirks & SDEV_NOTAGS) == 0)
273 *targ_flags |= TARF_TAG;
274 #endif
275 if (((quirks & SDEV_NOWIDE) == 0) &&
276 (sc->features & SF_BUS_WIDE))
277 *targ_flags |= TARF_WIDE;
278 if ((quirks & SDEV_NOSYNC) == 0)
279 *targ_flags |= TARF_SYNC;
280
281 if ((sc->features & SF_CHIP_GEBUG) &&
282 (*targ_flags & TARF_WIDE) == 0)
283 /*
284 * 1010 workaround: can't do disconnect if not wide,
285 * so can't do tag
286 */
287 *targ_flags &= ~TARF_TAG;
288
289 /* Safe to call siop_add_dev() multiple times */
290 siop_add_dev((struct siop_softc *)sc, target, lun);
291
292 if ((*targ_flags & TARF_DT) &&
293 (sc->mode == STEST4_MODE_LVD)) {
294 sc->targets[target]->status = TARST_PPR_NEG;
295 siop_ppr_msg(siop_cmd, msgoffset, sc->dt_minsync,
296 sc->maxoff);
297 } else if (*targ_flags & TARF_WIDE) {
298 sc->targets[target]->status = TARST_WIDE_NEG;
299 siop_wdtr_msg(siop_cmd, msgoffset,
300 MSG_EXT_WDTR_BUS_16_BIT);
301 } else if (*targ_flags & TARF_SYNC) {
302 sc->targets[target]->status = TARST_SYNC_NEG;
303 siop_sdtr_msg(siop_cmd, msgoffset, sc->st_minsync,
304 (sc->maxoff > 31) ? 31 : sc->maxoff);
305 } else {
306 sc->targets[target]->status = TARST_OK;
307 siop_update_xfer_mode(sc, target);
308 }
309 } else if (sc->targets[target]->status == TARST_OK &&
310 (*targ_flags & TARF_TAG) &&
311 siop_cmd->status != CMDST_SENSE) {
312 siop_cmd->flags |= CMDFL_TAG;
313 }
314 siop_cmd->siop_tables->status =
315 htole32(SCSI_SIOP_NOSTATUS); /* set invalid status */
316
317 if ((xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) ||
318 siop_cmd->status == CMDST_SENSE) {
319 bzero(siop_cmd->siop_tables->data,
320 sizeof(siop_cmd->siop_tables->data));
321 for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) {
322 siop_cmd->siop_tables->data[i].count =
323 htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len);
324 siop_cmd->siop_tables->data[i].addr =
325 htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr);
326 }
327 }
328 }
329
330 int
siop_wdtr_neg(siop_cmd)331 siop_wdtr_neg(siop_cmd)
332 struct siop_common_cmd *siop_cmd;
333 {
334 struct siop_common_softc *sc = siop_cmd->siop_sc;
335 struct siop_common_target *siop_target = siop_cmd->siop_target;
336 int target = siop_cmd->xs->sc_link->target;
337 struct siop_common_xfer *tables = siop_cmd->siop_tables;
338
339 if (siop_target->status == TARST_WIDE_NEG) {
340 /* we initiated wide negotiation */
341 switch (tables->msg_in[3]) {
342 case MSG_EXT_WDTR_BUS_8_BIT:
343 siop_target->flags &= ~TARF_ISWIDE;
344 sc->targets[target]->id &= ~(SCNTL3_EWS << 24);
345 break;
346 case MSG_EXT_WDTR_BUS_16_BIT:
347 if (siop_target->flags & TARF_WIDE) {
348 siop_target->flags |= TARF_ISWIDE;
349 sc->targets[target]->id |= (SCNTL3_EWS << 24);
350 break;
351 }
352 /* FALLTHROUH */
353 default:
354 /*
355 * hum, we got more than what we can handle, shouldn't
356 * happen. Reject, and stay async
357 */
358 siop_target->flags &= ~TARF_ISWIDE;
359 siop_target->status = TARST_OK;
360 siop_target->offset = siop_target->period = 0;
361 siop_update_xfer_mode(sc, target);
362 printf("%s: rejecting invalid wide negotiation from "
363 "target %d (%d)\n", sc->sc_dev.dv_xname, target,
364 tables->msg_in[3]);
365 tables->t_msgout.count= htole32(1);
366 tables->msg_out[0] = MSG_MESSAGE_REJECT;
367 return SIOP_NEG_MSGOUT;
368 }
369 tables->id = htole32(sc->targets[target]->id);
370 bus_space_write_1(sc->sc_rt, sc->sc_rh,
371 SIOP_SCNTL3,
372 (sc->targets[target]->id >> 24) & 0xff);
373 /* we now need to do sync */
374 if (siop_target->flags & TARF_SYNC) {
375 siop_target->status = TARST_SYNC_NEG;
376 siop_sdtr_msg(siop_cmd, 0, sc->st_minsync,
377 (sc->maxoff > 31) ? 31 : sc->maxoff);
378 return SIOP_NEG_MSGOUT;
379 } else {
380 siop_target->status = TARST_OK;
381 siop_update_xfer_mode(sc, target);
382 return SIOP_NEG_ACK;
383 }
384 } else {
385 /* target initiated wide negotiation */
386 if (tables->msg_in[3] >= MSG_EXT_WDTR_BUS_16_BIT
387 && (siop_target->flags & TARF_WIDE)) {
388 siop_target->flags |= TARF_ISWIDE;
389 sc->targets[target]->id |= SCNTL3_EWS << 24;
390 } else {
391 siop_target->flags &= ~TARF_ISWIDE;
392 sc->targets[target]->id &= ~(SCNTL3_EWS << 24);
393 }
394 tables->id = htole32(sc->targets[target]->id);
395 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3,
396 (sc->targets[target]->id >> 24) & 0xff);
397 /*
398 * we did reset wide parameters, so fall back to async,
399 * but don't schedule a sync neg, target should initiate it
400 */
401 siop_target->status = TARST_OK;
402 siop_target->offset = siop_target->period = 0;
403 siop_update_xfer_mode(sc, target);
404 siop_wdtr_msg(siop_cmd, 0, (siop_target->flags & TARF_ISWIDE) ?
405 MSG_EXT_WDTR_BUS_16_BIT : MSG_EXT_WDTR_BUS_8_BIT);
406 return SIOP_NEG_MSGOUT;
407 }
408 }
409
410 int
siop_ppr_neg(siop_cmd)411 siop_ppr_neg(siop_cmd)
412 struct siop_common_cmd *siop_cmd;
413 {
414 struct siop_common_softc *sc = siop_cmd->siop_sc;
415 struct siop_common_target *siop_target = siop_cmd->siop_target;
416 int target = siop_cmd->xs->sc_link->target;
417 struct siop_common_xfer *tables = siop_cmd->siop_tables;
418 int sync, offset, options, scf = 0;
419 int i;
420
421 #ifdef DEBUG_NEG
422 printf("%s: answer on ppr negotiation:", sc->sc_dev.dv_xname);
423 for (i = 0; i < 8; i++)
424 printf(" 0x%x", tables->msg_in[i]);
425 printf("\n");
426 #endif
427
428 if (siop_target->status == TARST_PPR_NEG) {
429 /* we initiated PPR negotiation */
430 sync = tables->msg_in[3];
431 offset = tables->msg_in[5];
432 options = tables->msg_in[7];
433 if (options != MSG_EXT_PPR_PROT_DT) {
434 /* should't happen */
435 printf("%s: ppr negotiation for target %d: "
436 "no DT option\n", sc->sc_dev.dv_xname, target);
437 siop_target->status = TARST_ASYNC;
438 siop_target->flags &= ~(TARF_DT | TARF_ISDT);
439 siop_target->offset = 0;
440 siop_target->period = 0;
441 goto reject;
442 }
443
444 if (offset > sc->maxoff || sync < sc->dt_minsync ||
445 sync > sc->dt_maxsync) {
446 printf("%s: ppr negotiation for target %d: "
447 "offset (%d) or sync (%d) out of range\n",
448 sc->sc_dev.dv_xname, target, offset, sync);
449 /* should not happen */
450 siop_target->status = TARST_ASYNC;
451 siop_target->flags &= ~(TARF_DT | TARF_ISDT);
452 siop_target->offset = 0;
453 siop_target->period = 0;
454 goto reject;
455 } else {
456 for (i = 0; i <
457 sizeof(dt_scf_period) / sizeof(dt_scf_period[0]);
458 i++) {
459 if (sc->clock_period != dt_scf_period[i].clock)
460 continue;
461 if (dt_scf_period[i].period == sync) {
462 /* ok, found it. we now are sync. */
463 siop_target->offset = offset;
464 siop_target->period = sync;
465 scf = dt_scf_period[i].scf;
466 siop_target->flags |= TARF_ISDT;
467 }
468 }
469 if ((siop_target->flags & TARF_ISDT) == 0) {
470 printf("%s: ppr negotiation for target %d: "
471 "sync (%d) incompatible with adapter\n",
472 sc->sc_dev.dv_xname, target, sync);
473 /*
474 * we didn't find it in our table, do async
475 * send reject msg, start SDTR/WDTR neg
476 */
477 siop_target->status = TARST_ASYNC;
478 siop_target->flags &= ~(TARF_DT | TARF_ISDT);
479 siop_target->offset = 0;
480 siop_target->period = 0;
481 goto reject;
482 }
483 }
484 if (tables->msg_in[6] != 1) {
485 printf("%s: ppr negotiation for target %d: "
486 "transfer width (%d) incompatible with dt\n",
487 sc->sc_dev.dv_xname, target, tables->msg_in[6]);
488 /* DT mode can only be done with wide transfers */
489 siop_target->status = TARST_ASYNC;
490 siop_target->flags &= ~(TARF_DT | TARF_ISDT);
491 siop_target->offset = 0;
492 siop_target->period = 0;
493 goto reject;
494 }
495 siop_target->flags |= TARF_ISWIDE;
496 sc->targets[target]->id |= (SCNTL3_EWS << 24);
497 sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24);
498 sc->targets[target]->id |= scf << (24 + SCNTL3_SCF_SHIFT);
499 sc->targets[target]->id &= ~(SXFER_MO_MASK << 8);
500 sc->targets[target]->id |=
501 (siop_target->offset & SXFER_MO_MASK) << 8;
502 sc->targets[target]->id &= ~0xff;
503 sc->targets[target]->id |= SCNTL4_U3EN;
504 siop_target->status = TARST_OK;
505 siop_update_xfer_mode(sc, target);
506 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3,
507 (sc->targets[target]->id >> 24) & 0xff);
508 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER,
509 (sc->targets[target]->id >> 8) & 0xff);
510 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL4,
511 sc->targets[target]->id & 0xff);
512 return SIOP_NEG_ACK;
513 } else {
514 /* target initiated PPR negotiation, shouldn't happen */
515 printf("%s: rejecting invalid PPR negotiation from "
516 "target %d\n", sc->sc_dev.dv_xname, target);
517 reject:
518 tables->t_msgout.count= htole32(1);
519 tables->msg_out[0] = MSG_MESSAGE_REJECT;
520 return SIOP_NEG_MSGOUT;
521 }
522 }
523
524 int
siop_sdtr_neg(siop_cmd)525 siop_sdtr_neg(siop_cmd)
526 struct siop_common_cmd *siop_cmd;
527 {
528 struct siop_common_softc *sc = siop_cmd->siop_sc;
529 struct siop_common_target *siop_target = siop_cmd->siop_target;
530 int target = siop_cmd->xs->sc_link->target;
531 int sync, maxoffset, offset, i;
532 int send_msgout = 0;
533 struct siop_common_xfer *tables = siop_cmd->siop_tables;
534
535 /* limit to Ultra/2 parameters, need PPR for Ultra/3 */
536 maxoffset = (sc->maxoff > 31) ? 31 : sc->maxoff;
537
538 sync = tables->msg_in[3];
539 offset = tables->msg_in[4];
540
541 if (siop_target->status == TARST_SYNC_NEG) {
542 /* we initiated sync negotiation */
543 siop_target->status = TARST_OK;
544 #ifdef DEBUG
545 printf("sdtr: sync %d offset %d\n", sync, offset);
546 #endif
547 if (offset > maxoffset || sync < sc->st_minsync ||
548 sync > sc->st_maxsync)
549 goto reject;
550 for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]);
551 i++) {
552 if (sc->clock_period != scf_period[i].clock)
553 continue;
554 if (scf_period[i].period == sync) {
555 /* ok, found it. we now are sync. */
556 siop_target->offset = offset;
557 siop_target->period = sync;
558 sc->targets[target]->id &=
559 ~(SCNTL3_SCF_MASK << 24);
560 sc->targets[target]->id |= scf_period[i].scf
561 << (24 + SCNTL3_SCF_SHIFT);
562 if (sync < 25 && /* Ultra */
563 (sc->features & SF_BUS_ULTRA3) == 0)
564 sc->targets[target]->id |=
565 SCNTL3_ULTRA << 24;
566 else
567 sc->targets[target]->id &=
568 ~(SCNTL3_ULTRA << 24);
569 sc->targets[target]->id &=
570 ~(SXFER_MO_MASK << 8);
571 sc->targets[target]->id |=
572 (offset & SXFER_MO_MASK) << 8;
573 sc->targets[target]->id &= ~0xff; /* scntl4 */
574 goto end;
575 }
576 }
577 /*
578 * we didn't find it in our table, do async and send reject
579 * msg
580 */
581 reject:
582 send_msgout = 1;
583 tables->t_msgout.count= htole32(1);
584 tables->msg_out[0] = MSG_MESSAGE_REJECT;
585 sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24);
586 sc->targets[target]->id &= ~(SCNTL3_ULTRA << 24);
587 sc->targets[target]->id &= ~(SXFER_MO_MASK << 8);
588 sc->targets[target]->id &= ~0xff; /* scntl4 */
589 siop_target->offset = siop_target->period = 0;
590 } else { /* target initiated sync neg */
591 #ifdef DEBUG
592 printf("sdtr (target): sync %d offset %d\n", sync, offset);
593 #endif
594 if (offset == 0 || sync > sc->st_maxsync) { /* async */
595 goto async;
596 }
597 if (offset > maxoffset)
598 offset = maxoffset;
599 if (sync < sc->st_minsync)
600 sync = sc->st_minsync;
601 /* look for sync period */
602 for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]);
603 i++) {
604 if (sc->clock_period != scf_period[i].clock)
605 continue;
606 if (scf_period[i].period == sync) {
607 /* ok, found it. we now are sync. */
608 siop_target->offset = offset;
609 siop_target->period = sync;
610 sc->targets[target]->id &=
611 ~(SCNTL3_SCF_MASK << 24);
612 sc->targets[target]->id |= scf_period[i].scf
613 << (24 + SCNTL3_SCF_SHIFT);
614 if (sync < 25 && /* Ultra */
615 (sc->features & SF_BUS_ULTRA3) == 0)
616 sc->targets[target]->id |=
617 SCNTL3_ULTRA << 24;
618 else
619 sc->targets[target]->id &=
620 ~(SCNTL3_ULTRA << 24);
621 sc->targets[target]->id &=
622 ~(SXFER_MO_MASK << 8);
623 sc->targets[target]->id |=
624 (offset & SXFER_MO_MASK) << 8;
625 sc->targets[target]->id &= ~0xff; /* scntl4 */
626 siop_sdtr_msg(siop_cmd, 0, sync, offset);
627 send_msgout = 1;
628 goto end;
629 }
630 }
631 async:
632 siop_target->offset = siop_target->period = 0;
633 sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24);
634 sc->targets[target]->id &= ~(SCNTL3_ULTRA << 24);
635 sc->targets[target]->id &= ~(SXFER_MO_MASK << 8);
636 sc->targets[target]->id &= ~0xff; /* scntl4 */
637 siop_sdtr_msg(siop_cmd, 0, 0, 0);
638 send_msgout = 1;
639 }
640 end:
641 if (siop_target->status == TARST_OK)
642 siop_update_xfer_mode(sc, target);
643 #ifdef DEBUG
644 printf("id now 0x%x\n", sc->targets[target]->id);
645 #endif
646 tables->id = htole32(sc->targets[target]->id);
647 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3,
648 (sc->targets[target]->id >> 24) & 0xff);
649 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER,
650 (sc->targets[target]->id >> 8) & 0xff);
651 if (send_msgout) {
652 return SIOP_NEG_MSGOUT;
653 } else {
654 return SIOP_NEG_ACK;
655 }
656 }
657
658 void
siop_sdtr_msg(siop_cmd,offset,ssync,soff)659 siop_sdtr_msg(siop_cmd, offset, ssync, soff)
660 struct siop_common_cmd *siop_cmd;
661 int offset;
662 int ssync, soff;
663 {
664 siop_cmd->siop_tables->msg_out[offset + 0] = MSG_EXTENDED;
665 siop_cmd->siop_tables->msg_out[offset + 1] = MSG_EXT_SDTR_LEN;
666 siop_cmd->siop_tables->msg_out[offset + 2] = MSG_EXT_SDTR;
667 siop_cmd->siop_tables->msg_out[offset + 3] = ssync;
668 siop_cmd->siop_tables->msg_out[offset + 4] = soff;
669 siop_cmd->siop_tables->t_msgout.count =
670 htole32(offset + MSG_EXT_SDTR_LEN + 2);
671 }
672
673 void
siop_wdtr_msg(siop_cmd,offset,wide)674 siop_wdtr_msg(siop_cmd, offset, wide)
675 struct siop_common_cmd *siop_cmd;
676 int offset;
677 int wide;
678 {
679 siop_cmd->siop_tables->msg_out[offset + 0] = MSG_EXTENDED;
680 siop_cmd->siop_tables->msg_out[offset + 1] = MSG_EXT_WDTR_LEN;
681 siop_cmd->siop_tables->msg_out[offset + 2] = MSG_EXT_WDTR;
682 siop_cmd->siop_tables->msg_out[offset + 3] = wide;
683 siop_cmd->siop_tables->t_msgout.count =
684 htole32(offset + MSG_EXT_WDTR_LEN + 2);
685 }
686
687 void
siop_ppr_msg(siop_cmd,offset,ssync,soff)688 siop_ppr_msg(siop_cmd, offset, ssync, soff)
689 struct siop_common_cmd *siop_cmd;
690 int offset;
691 int ssync, soff;
692 {
693 siop_cmd->siop_tables->msg_out[offset + 0] = MSG_EXTENDED;
694 siop_cmd->siop_tables->msg_out[offset + 1] = MSG_EXT_PPR_LEN;
695 siop_cmd->siop_tables->msg_out[offset + 2] = MSG_EXT_PPR;
696 siop_cmd->siop_tables->msg_out[offset + 3] = ssync;
697 siop_cmd->siop_tables->msg_out[offset + 4] = 0; /* reserved */
698 siop_cmd->siop_tables->msg_out[offset + 5] = soff;
699 siop_cmd->siop_tables->msg_out[offset + 6] = 1; /* wide */
700 siop_cmd->siop_tables->msg_out[offset + 7] = MSG_EXT_PPR_PROT_DT;
701 siop_cmd->siop_tables->t_msgout.count =
702 htole32(offset + MSG_EXT_PPR_LEN + 2);
703 }
704
705 void
siop_minphys(bp)706 siop_minphys(bp)
707 struct buf *bp;
708 {
709 minphys(bp);
710 }
711
712 void
siop_sdp(siop_cmd)713 siop_sdp(siop_cmd)
714 struct siop_common_cmd *siop_cmd;
715 {
716 /* save data pointer. Handle async only for now */
717 int offset, dbc, sstat;
718 struct siop_common_softc *sc = siop_cmd->siop_sc;
719 scr_table_t *table; /* table to patch */
720
721 if ((siop_cmd->xs->flags & (SCSI_DATA_OUT | SCSI_DATA_IN))
722 == 0)
723 return; /* no data pointers to save */
724 offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA + 1);
725 if (offset >= SIOP_NSG) {
726 printf("%s: bad offset in siop_sdp (%d)\n",
727 sc->sc_dev.dv_xname, offset);
728 return;
729 }
730 table = &siop_cmd->siop_tables->data[offset];
731 #ifdef DEBUG_DR
732 printf("sdp: offset %d count=%d addr=0x%x ", offset,
733 letoh32(table->count), letoh32(table->addr));
734 #endif
735 dbc = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DBC) & 0x00ffffff;
736 if (siop_cmd->xs->flags & SCSI_DATA_OUT) {
737 if (sc->features & SF_CHIP_DFBC) {
738 dbc +=
739 bus_space_read_2(sc->sc_rt, sc->sc_rh, SIOP_DFBC);
740 } else {
741 /* need to account stale data in FIFO */
742 int dfifo =
743 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DFIFO);
744 if (sc->features & SF_CHIP_FIFO) {
745 dfifo |= (bus_space_read_1(sc->sc_rt, sc->sc_rh,
746 SIOP_CTEST5) & CTEST5_BOMASK) << 8;
747 dbc += (dfifo - (dbc & 0x3ff)) & 0x3ff;
748 } else {
749 dbc += (dfifo - (dbc & 0x7f)) & 0x7f;
750 }
751 }
752 sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT0);
753 if (sstat & SSTAT0_OLF)
754 dbc++;
755 if ((sstat & SSTAT0_ORF) && (sc->features & SF_CHIP_DFBC) == 0)
756 dbc++;
757 if (siop_cmd->siop_target->flags & TARF_ISWIDE) {
758 sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh,
759 SIOP_SSTAT2);
760 if (sstat & SSTAT2_OLF1)
761 dbc++;
762 if ((sstat & SSTAT2_ORF1) &&
763 (sc->features & SF_CHIP_DFBC) == 0)
764 dbc++;
765 }
766 /* clear the FIFO */
767 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
768 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) |
769 CTEST3_CLF);
770 }
771 table->addr =
772 htole32(letoh32(table->addr) + letoh32(table->count) - dbc);
773 table->count = htole32(dbc);
774 #ifdef DEBUG_DR
775 printf("now count=%d addr=0x%x\n",
776 letoh32(table->count), letoh32(table->addr));
777 #endif
778 }
779
780 void
siop_clearfifo(sc)781 siop_clearfifo(sc)
782 struct siop_common_softc *sc;
783 {
784 int timeout = 0;
785 int ctest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3);
786
787 #ifdef DEBUG_INTR
788 printf("DMA fifo not empty !\n");
789 #endif
790 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
791 ctest3 | CTEST3_CLF);
792 while ((bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) &
793 CTEST3_CLF) != 0) {
794 delay(1);
795 if (++timeout > 1000) {
796 printf("clear fifo failed\n");
797 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
798 bus_space_read_1(sc->sc_rt, sc->sc_rh,
799 SIOP_CTEST3) & ~CTEST3_CLF);
800 return;
801 }
802 }
803 }
804
805 int
siop_modechange(sc)806 siop_modechange(sc)
807 struct siop_common_softc *sc;
808 {
809 int retry;
810 int sist0, sist1, stest2;
811 for (retry = 0; retry < 5; retry++) {
812 /*
813 * datasheet says to wait 100ms and re-read SIST1,
814 * to check that DIFFSENSE is stable.
815 * We may delay() 5 times for 100ms at interrupt time;
816 * hopefully this will not happen often.
817 */
818 delay(100000);
819 sist0 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST0);
820 sist1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST1);
821 if (sist1 & SIEN1_SBMC)
822 continue; /* we got an irq again */
823 sc->mode = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST4) &
824 STEST4_MODE_MASK;
825 stest2 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2);
826 switch(sc->mode) {
827 case STEST4_MODE_DIF:
828 printf("%s: switching to differential mode\n",
829 sc->sc_dev.dv_xname);
830 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2,
831 stest2 | STEST2_DIF);
832 break;
833 case STEST4_MODE_SE:
834 printf("%s: switching to single-ended mode\n",
835 sc->sc_dev.dv_xname);
836 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2,
837 stest2 & ~STEST2_DIF);
838 break;
839 case STEST4_MODE_LVD:
840 printf("%s: switching to LVD mode\n",
841 sc->sc_dev.dv_xname);
842 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2,
843 stest2 & ~STEST2_DIF);
844 break;
845 default:
846 printf("%s: invalid SCSI mode 0x%x\n",
847 sc->sc_dev.dv_xname, sc->mode);
848 return 0;
849 }
850 return 1;
851 }
852 printf("%s: timeout waiting for DIFFSENSE to stabilise\n",
853 sc->sc_dev.dv_xname);
854 return 0;
855 }
856
857 void
siop_resetbus(sc)858 siop_resetbus(sc)
859 struct siop_common_softc *sc;
860 {
861 int scntl1;
862 scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1);
863 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1,
864 scntl1 | SCNTL1_RST);
865 /* minimum 25 us, more time won't hurt */
866 delay(100);
867 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);
868 }
869
870 void
siop_update_xfer_mode(sc,target)871 siop_update_xfer_mode(sc, target)
872 struct siop_common_softc *sc;
873 int target;
874 {
875 struct siop_common_target *siop_target;
876
877 siop_target = sc->targets[target];
878
879 printf("%s: target %d now using %s%s%d bit ",
880 sc->sc_dev.dv_xname, target,
881 (siop_target->flags & TARF_TAG) ? "tagged " : "",
882 (siop_target->flags & TARF_ISDT) ? "DT " : "",
883 (siop_target->flags & TARF_ISWIDE) ? 16 : 8);
884
885 if (siop_target->offset == 0)
886 printf("async ");
887 else {
888 switch (siop_target->period) {
889 case 9: /* 12.5ns cycle */
890 printf("80.0");
891 break;
892 case 10: /* 25 ns cycle */
893 printf("40.0");
894 break;
895 case 12: /* 48 ns cycle */
896 printf("20.0");
897 break;
898 case 18: /* 72 ns cycle */
899 printf("13.3");
900 break;
901 case 25: /* 100 ns cycle */
902 printf("10.0");
903 break;
904 case 37: /* 118 ns cycle */
905 printf("6.67");
906 break;
907 case 50: /* 200 ns cycle */
908 printf("5.0");
909 break;
910 case 75: /* 300 ns cycle */
911 printf("3.33");
912 break;
913 default:
914 printf("??");
915 break;
916 }
917 printf(" MHz %d REQ/ACK offset ", siop_target->offset);
918 }
919
920 printf("xfers\n");
921
922 if ((sc->features & SF_CHIP_GEBUG) &&
923 (siop_target->flags & TARF_ISWIDE) == 0)
924 /* 1010 workaround: can't do disconnect if not wide, so can't do tag */
925 siop_target->flags &= ~TARF_TAG;
926 }
927