xref: /openbsd-src/sys/dev/ic/siop_common.c (revision db3296cf5c1dd9058ceecc3a29fe4aaa0bd26000)
1 /*	$OpenBSD: siop_common.c,v 1.16 2003/07/01 17:15:06 krw 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
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
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
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 		if ((quirks & SDEV_NOTAGS) == 0)
272 			*targ_flags |= TARF_TAG;
273 		if (((quirks & SDEV_NOWIDE) == 0) &&
274 		    (sc->features & SF_BUS_WIDE))
275 			*targ_flags |= TARF_WIDE;
276 		if ((quirks & SDEV_NOSYNC) == 0)
277 			*targ_flags |= TARF_SYNC;
278 
279 		if ((sc->features & SF_CHIP_GEBUG) &&
280 		    (*targ_flags & TARF_WIDE) == 0)
281 			/*
282 			 * 1010 workaround: can't do disconnect if not wide,
283 			 * so can't do tag
284 			 */
285 			*targ_flags &= ~TARF_TAG;
286 
287 		/* Safe to call siop_add_dev() multiple times */
288 		siop_add_dev((struct siop_softc *)sc, target, lun);
289 
290 		if ((*targ_flags & TARF_DT) &&
291 		    (sc->mode == STEST4_MODE_LVD)) {
292 			sc->targets[target]->status = TARST_PPR_NEG;
293 			 siop_ppr_msg(siop_cmd, msgoffset, sc->dt_minsync,
294 			    sc->maxoff);
295 		} else if (*targ_flags & TARF_WIDE) {
296 			sc->targets[target]->status = TARST_WIDE_NEG;
297 			siop_wdtr_msg(siop_cmd, msgoffset,
298 			    MSG_EXT_WDTR_BUS_16_BIT);
299 		} else if (*targ_flags & TARF_SYNC) {
300 			sc->targets[target]->status = TARST_SYNC_NEG;
301 			siop_sdtr_msg(siop_cmd, msgoffset, sc->st_minsync,
302 			(sc->maxoff > 31) ? 31 :  sc->maxoff);
303 		} else {
304 			sc->targets[target]->status = TARST_OK;
305 			siop_update_xfer_mode(sc, target);
306 		}
307 	} else if (sc->targets[target]->status == TARST_OK &&
308 	    (*targ_flags & TARF_TAG) &&
309 	    siop_cmd->status != CMDST_SENSE) {
310 		siop_cmd->flags |= CMDFL_TAG;
311 	}
312 	siop_cmd->siop_tables->status =
313 	    htole32(SCSI_SIOP_NOSTATUS); /* set invalid status */
314 
315 	if ((xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) ||
316 	    siop_cmd->status == CMDST_SENSE) {
317 		for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) {
318 			siop_cmd->siop_tables->data[i].count =
319 			    htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len);
320 			siop_cmd->siop_tables->data[i].addr =
321 			    htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr);
322 		}
323 	}
324 }
325 
326 int
327 siop_wdtr_neg(siop_cmd)
328 	struct siop_common_cmd *siop_cmd;
329 {
330 	struct siop_common_softc *sc = siop_cmd->siop_sc;
331 	struct siop_common_target *siop_target = siop_cmd->siop_target;
332 	int target = siop_cmd->xs->sc_link->target;
333 	struct siop_common_xfer *tables = siop_cmd->siop_tables;
334 
335 	if (siop_target->status == TARST_WIDE_NEG) {
336 		/* we initiated wide negotiation */
337 		switch (tables->msg_in[3]) {
338 		case MSG_EXT_WDTR_BUS_8_BIT:
339 			siop_target->flags &= ~TARF_ISWIDE;
340 			sc->targets[target]->id &= ~(SCNTL3_EWS << 24);
341 			break;
342 		case MSG_EXT_WDTR_BUS_16_BIT:
343 			if (siop_target->flags & TARF_WIDE) {
344 				siop_target->flags |= TARF_ISWIDE;
345 				sc->targets[target]->id |= (SCNTL3_EWS << 24);
346 				break;
347 			}
348 		/* FALLTHROUH */
349 		default:
350 			/*
351  			 * hum, we got more than what we can handle, shouldn't
352 			 * happen. Reject, and stay async
353 			 */
354 			siop_target->flags &= ~TARF_ISWIDE;
355 			siop_target->status = TARST_OK;
356 			siop_target->offset = siop_target->period = 0;
357 			siop_update_xfer_mode(sc, target);
358 			printf("%s: rejecting invalid wide negotiation from "
359 			    "target %d (%d)\n", sc->sc_dev.dv_xname, target,
360 			    tables->msg_in[3]);
361 			tables->t_msgout.count= htole32(1);
362 			tables->msg_out[0] = MSG_MESSAGE_REJECT;
363 			return SIOP_NEG_MSGOUT;
364 		}
365 		tables->id = htole32(sc->targets[target]->id);
366 		bus_space_write_1(sc->sc_rt, sc->sc_rh,
367 		    SIOP_SCNTL3,
368 		    (sc->targets[target]->id >> 24) & 0xff);
369 		/* we now need to do sync */
370 		if (siop_target->flags & TARF_SYNC) {
371 			siop_target->status = TARST_SYNC_NEG;
372 			siop_sdtr_msg(siop_cmd, 0, sc->st_minsync,
373 			    (sc->maxoff > 31) ? 31 : sc->maxoff);
374 			return SIOP_NEG_MSGOUT;
375 		} else {
376 			siop_target->status = TARST_OK;
377 			siop_update_xfer_mode(sc, target);
378 			return SIOP_NEG_ACK;
379 		}
380 	} else {
381 		/* target initiated wide negotiation */
382 		if (tables->msg_in[3] >= MSG_EXT_WDTR_BUS_16_BIT
383 		    && (siop_target->flags & TARF_WIDE)) {
384 			siop_target->flags |= TARF_ISWIDE;
385 			sc->targets[target]->id |= SCNTL3_EWS << 24;
386 		} else {
387 			siop_target->flags &= ~TARF_ISWIDE;
388 			sc->targets[target]->id &= ~(SCNTL3_EWS << 24);
389 		}
390 		tables->id = htole32(sc->targets[target]->id);
391 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3,
392 		    (sc->targets[target]->id >> 24) & 0xff);
393 		/*
394 		 * we did reset wide parameters, so fall back to async,
395 		 * but don't schedule a sync neg, target should initiate it
396 		 */
397 		siop_target->status = TARST_OK;
398 		siop_target->offset = siop_target->period = 0;
399 		siop_update_xfer_mode(sc, target);
400 		siop_wdtr_msg(siop_cmd, 0, (siop_target->flags & TARF_ISWIDE) ?
401 		    MSG_EXT_WDTR_BUS_16_BIT : MSG_EXT_WDTR_BUS_8_BIT);
402 		return SIOP_NEG_MSGOUT;
403 	}
404 }
405 
406 int
407 siop_ppr_neg(siop_cmd)
408 	struct siop_common_cmd *siop_cmd;
409 {
410 	struct siop_common_softc *sc = siop_cmd->siop_sc;
411 	struct siop_common_target *siop_target = siop_cmd->siop_target;
412 	int target = siop_cmd->xs->sc_link->target;
413 	struct siop_common_xfer *tables = siop_cmd->siop_tables;
414 	int sync, offset, options, scf = 0;
415 	int i;
416 
417 #ifdef DEBUG_NEG
418 	printf("%s: answer on ppr negotiation:", sc->sc_dev.dv_xname);
419 	for (i = 0; i < 8; i++)
420 		printf(" 0x%x", tables->msg_in[i]);
421 	printf("\n");
422 #endif
423 
424 	if (siop_target->status == TARST_PPR_NEG) {
425 		/* we initiated PPR negotiation */
426 		sync = tables->msg_in[3];
427 		offset = tables->msg_in[5];
428 		options = tables->msg_in[7];
429 		if (options != MSG_EXT_PPR_PROT_DT) {
430 			/* should't happen */
431 			printf("%s: ppr negotiation for target %d: "
432 			    "no DT option\n", sc->sc_dev.dv_xname, target);
433 			siop_target->status = TARST_ASYNC;
434 			siop_target->flags &= ~(TARF_DT | TARF_ISDT);
435 			siop_target->offset = 0;
436 			siop_target->period = 0;
437 			goto reject;
438 		}
439 
440 		if (offset > sc->maxoff || sync < sc->dt_minsync ||
441 		    sync > sc->dt_maxsync) {
442 			printf("%s: ppr negotiation for target %d: "
443 			    "offset (%d) or sync (%d) out of range\n",
444 			    sc->sc_dev.dv_xname, target, offset, sync);
445 			/* should not happen */
446 			siop_target->status = TARST_ASYNC;
447 			siop_target->flags &= ~(TARF_DT | TARF_ISDT);
448 			siop_target->offset = 0;
449 			siop_target->period = 0;
450 			goto reject;
451 		} else {
452 			for (i = 0; i <
453 			    sizeof(dt_scf_period) / sizeof(dt_scf_period[0]);
454 			    i++) {
455 				if (sc->clock_period != dt_scf_period[i].clock)
456 					continue;
457 				if (dt_scf_period[i].period == sync) {
458 					/* ok, found it. we now are sync. */
459 					siop_target->offset = offset;
460 					siop_target->period = sync;
461 					scf = dt_scf_period[i].scf;
462 					siop_target->flags |= TARF_ISDT;
463 				}
464 			}
465 			if ((siop_target->flags & TARF_ISDT) == 0) {
466 				printf("%s: ppr negotiation for target %d: "
467 				    "sync (%d) incompatible with adapter\n",
468 				    sc->sc_dev.dv_xname, target, sync);
469 				/*
470 				 * we didn't find it in our table, do async
471 				 * send reject msg, start SDTR/WDTR neg
472 				 */
473 				siop_target->status = TARST_ASYNC;
474 				siop_target->flags &= ~(TARF_DT | TARF_ISDT);
475 				siop_target->offset = 0;
476 				siop_target->period = 0;
477 				goto reject;
478 			}
479 		}
480 		if (tables->msg_in[6] != 1) {
481 			printf("%s: ppr negotiation for target %d: "
482 			    "transfer width (%d) incompatible with dt\n",
483 			    sc->sc_dev.dv_xname, target, tables->msg_in[6]);
484 			/* DT mode can only be done with wide transfers */
485 			siop_target->status = TARST_ASYNC;
486 			siop_target->flags &= ~(TARF_DT | TARF_ISDT);
487 			siop_target->offset = 0;
488 			siop_target->period = 0;
489 			goto reject;
490 		}
491 		siop_target->flags |= TARF_ISWIDE;
492 		sc->targets[target]->id |= (SCNTL3_EWS << 24);
493 		sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24);
494 		sc->targets[target]->id |= scf << (24 + SCNTL3_SCF_SHIFT);
495 		sc->targets[target]->id &= ~(SXFER_MO_MASK << 8);
496 		sc->targets[target]->id |=
497 		    (siop_target->offset & SXFER_MO_MASK) << 8;
498 		sc->targets[target]->id &= ~0xff;
499 		sc->targets[target]->id |= SCNTL4_U3EN;
500 		siop_target->status = TARST_OK;
501 		siop_update_xfer_mode(sc, target);
502 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3,
503 		    (sc->targets[target]->id >> 24) & 0xff);
504 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER,
505 		    (sc->targets[target]->id >> 8) & 0xff);
506 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL4,
507 		    sc->targets[target]->id & 0xff);
508 		return SIOP_NEG_ACK;
509 	} else {
510 		/* target initiated PPR negotiation, shouldn't happen */
511 		printf("%s: rejecting invalid PPR negotiation from "
512 		    "target %d\n", sc->sc_dev.dv_xname, target);
513 reject:
514 		tables->t_msgout.count= htole32(1);
515 		tables->msg_out[0] = MSG_MESSAGE_REJECT;
516 		return SIOP_NEG_MSGOUT;
517 	}
518 }
519 
520 int
521 siop_sdtr_neg(siop_cmd)
522 	struct siop_common_cmd *siop_cmd;
523 {
524 	struct siop_common_softc *sc = siop_cmd->siop_sc;
525 	struct siop_common_target *siop_target = siop_cmd->siop_target;
526 	int target = siop_cmd->xs->sc_link->target;
527 	int sync, maxoffset, offset, i;
528 	int send_msgout = 0;
529 	struct siop_common_xfer *tables = siop_cmd->siop_tables;
530 
531 	/* limit to Ultra/2 parameters, need PPR for Ultra/3 */
532 	maxoffset = (sc->maxoff > 31) ? 31 : sc->maxoff;
533 
534 	sync = tables->msg_in[3];
535 	offset = tables->msg_in[4];
536 
537 	if (siop_target->status == TARST_SYNC_NEG) {
538 		/* we initiated sync negotiation */
539 		siop_target->status = TARST_OK;
540 #ifdef DEBUG
541 		printf("sdtr: sync %d offset %d\n", sync, offset);
542 #endif
543 		if (offset > maxoffset || sync < sc->st_minsync ||
544 			sync > sc->st_maxsync)
545 			goto reject;
546 		for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]);
547 		    i++) {
548 			if (sc->clock_period != scf_period[i].clock)
549 				continue;
550 			if (scf_period[i].period == sync) {
551 				/* ok, found it. we now are sync. */
552 				siop_target->offset = offset;
553 				siop_target->period = sync;
554 				sc->targets[target]->id &=
555 				    ~(SCNTL3_SCF_MASK << 24);
556 				sc->targets[target]->id |= scf_period[i].scf
557 				    << (24 + SCNTL3_SCF_SHIFT);
558 				if (sync < 25 && /* Ultra */
559 				    (sc->features & SF_BUS_ULTRA3) == 0)
560 					sc->targets[target]->id |=
561 					    SCNTL3_ULTRA << 24;
562 				else
563 					sc->targets[target]->id &=
564 					    ~(SCNTL3_ULTRA << 24);
565 				sc->targets[target]->id &=
566 				    ~(SXFER_MO_MASK << 8);
567 				sc->targets[target]->id |=
568 				    (offset & SXFER_MO_MASK) << 8;
569 				sc->targets[target]->id &= ~0xff; /* scntl4 */
570 				goto end;
571 			}
572 		}
573 		/*
574 		 * we didn't find it in our table, do async and send reject
575 		 * msg
576 		 */
577 reject:
578 		send_msgout = 1;
579 		tables->t_msgout.count= htole32(1);
580 		tables->msg_out[0] = MSG_MESSAGE_REJECT;
581 		sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24);
582 		sc->targets[target]->id &= ~(SCNTL3_ULTRA << 24);
583 		sc->targets[target]->id &= ~(SXFER_MO_MASK << 8);
584 		sc->targets[target]->id &= ~0xff; /* scntl4 */
585 		siop_target->offset = siop_target->period = 0;
586 	} else { /* target initiated sync neg */
587 #ifdef DEBUG
588 		printf("sdtr (target): sync %d offset %d\n", sync, offset);
589 #endif
590 		if (offset == 0 || sync > sc->st_maxsync) { /* async */
591 			goto async;
592 		}
593 		if (offset > maxoffset)
594 			offset = maxoffset;
595 		if (sync < sc->st_minsync)
596 			sync = sc->st_minsync;
597 		/* look for sync period */
598 		for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]);
599 		    i++) {
600 			if (sc->clock_period != scf_period[i].clock)
601 				continue;
602 			if (scf_period[i].period == sync) {
603 				/* ok, found it. we now are sync. */
604 				siop_target->offset = offset;
605 				siop_target->period = sync;
606 				sc->targets[target]->id &=
607 				    ~(SCNTL3_SCF_MASK << 24);
608 				sc->targets[target]->id |= scf_period[i].scf
609 				    << (24 + SCNTL3_SCF_SHIFT);
610 				if (sync < 25 && /* Ultra */
611 				    (sc->features & SF_BUS_ULTRA3) == 0)
612 					sc->targets[target]->id |=
613 					    SCNTL3_ULTRA << 24;
614 				else
615 					sc->targets[target]->id &=
616 					    ~(SCNTL3_ULTRA << 24);
617 				sc->targets[target]->id &=
618 				    ~(SXFER_MO_MASK << 8);
619 				sc->targets[target]->id |=
620 				    (offset & SXFER_MO_MASK) << 8;
621 				sc->targets[target]->id &= ~0xff; /* scntl4 */
622 				siop_sdtr_msg(siop_cmd, 0, sync, offset);
623 				send_msgout = 1;
624 				goto end;
625 			}
626 		}
627 async:
628 		siop_target->offset = siop_target->period = 0;
629 		sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24);
630 		sc->targets[target]->id &= ~(SCNTL3_ULTRA << 24);
631 		sc->targets[target]->id &= ~(SXFER_MO_MASK << 8);
632 		sc->targets[target]->id &= ~0xff; /* scntl4 */
633 		siop_sdtr_msg(siop_cmd, 0, 0, 0);
634 		send_msgout = 1;
635 	}
636 end:
637 	if (siop_target->status == TARST_OK)
638 		siop_update_xfer_mode(sc, target);
639 #ifdef DEBUG
640 	printf("id now 0x%x\n", sc->targets[target]->id);
641 #endif
642 	tables->id = htole32(sc->targets[target]->id);
643 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3,
644 	    (sc->targets[target]->id >> 24) & 0xff);
645 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER,
646 	    (sc->targets[target]->id >> 8) & 0xff);
647 	if (send_msgout) {
648 		return SIOP_NEG_MSGOUT;
649 	} else {
650 		return SIOP_NEG_ACK;
651 	}
652 }
653 
654 void
655 siop_sdtr_msg(siop_cmd, offset, ssync, soff)
656 	struct siop_common_cmd *siop_cmd;
657 	int offset;
658 	int ssync, soff;
659 {
660 	siop_cmd->siop_tables->msg_out[offset + 0] = MSG_EXTENDED;
661 	siop_cmd->siop_tables->msg_out[offset + 1] = MSG_EXT_SDTR_LEN;
662 	siop_cmd->siop_tables->msg_out[offset + 2] = MSG_EXT_SDTR;
663 	siop_cmd->siop_tables->msg_out[offset + 3] = ssync;
664 	siop_cmd->siop_tables->msg_out[offset + 4] = soff;
665 	siop_cmd->siop_tables->t_msgout.count =
666 	    htole32(offset + MSG_EXT_SDTR_LEN + 2);
667 }
668 
669 void
670 siop_wdtr_msg(siop_cmd, offset, wide)
671 	struct siop_common_cmd *siop_cmd;
672 	int offset;
673 {
674 	siop_cmd->siop_tables->msg_out[offset + 0] = MSG_EXTENDED;
675 	siop_cmd->siop_tables->msg_out[offset + 1] = MSG_EXT_WDTR_LEN;
676 	siop_cmd->siop_tables->msg_out[offset + 2] = MSG_EXT_WDTR;
677 	siop_cmd->siop_tables->msg_out[offset + 3] = wide;
678 	siop_cmd->siop_tables->t_msgout.count =
679 	    htole32(offset + MSG_EXT_WDTR_LEN + 2);
680 }
681 
682 void
683 siop_ppr_msg(siop_cmd, offset, ssync, soff)
684 	struct siop_common_cmd *siop_cmd;
685 	int offset;
686 	int ssync, soff;
687 {
688 	siop_cmd->siop_tables->msg_out[offset + 0] = MSG_EXTENDED;
689 	siop_cmd->siop_tables->msg_out[offset + 1] = MSG_EXT_PPR_LEN;
690 	siop_cmd->siop_tables->msg_out[offset + 2] = MSG_EXT_PPR;
691 	siop_cmd->siop_tables->msg_out[offset + 3] = ssync;
692 	siop_cmd->siop_tables->msg_out[offset + 4] = 0; /* reserved */
693 	siop_cmd->siop_tables->msg_out[offset + 5] = soff;
694 	siop_cmd->siop_tables->msg_out[offset + 6] = 1; /* wide */
695 	siop_cmd->siop_tables->msg_out[offset + 7] = MSG_EXT_PPR_PROT_DT;
696 	siop_cmd->siop_tables->t_msgout.count =
697 	    htole32(offset + MSG_EXT_PPR_LEN + 2);
698 }
699 
700 void
701 siop_minphys(bp)
702 	struct buf *bp;
703 {
704 	minphys(bp);
705 }
706 
707 void
708 siop_sdp(siop_cmd)
709 	struct siop_common_cmd *siop_cmd;
710 {
711 	/* save data pointer. Handle async only for now */
712 	int offset, dbc, sstat;
713 	struct siop_common_softc *sc = siop_cmd->siop_sc;
714 	scr_table_t *table; /* table to patch */
715 
716 	if ((siop_cmd->xs->flags & (SCSI_DATA_OUT | SCSI_DATA_IN))
717 	    == 0)
718 	    return; /* no data pointers to save */
719 	offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA + 1);
720 	if (offset >= SIOP_NSG) {
721 		printf("%s: bad offset in siop_sdp (%d)\n",
722 		    sc->sc_dev.dv_xname, offset);
723 		return;
724 	}
725 	table = &siop_cmd->siop_tables->data[offset];
726 #ifdef DEBUG_DR
727 	printf("sdp: offset %d count=%d addr=0x%x ", offset,
728 	    letoh32(table->count), letoh32(table->addr));
729 #endif
730 	dbc = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DBC) & 0x00ffffff;
731 	if (siop_cmd->xs->flags & SCSI_DATA_OUT) {
732 		if (sc->features & SF_CHIP_DFBC) {
733 			dbc +=
734 			    bus_space_read_2(sc->sc_rt, sc->sc_rh, SIOP_DFBC);
735 		} else {
736 			/* need to account stale data in FIFO */
737 			int dfifo =
738 			    bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DFIFO);
739 			if (sc->features & SF_CHIP_FIFO) {
740 				dfifo |= (bus_space_read_1(sc->sc_rt, sc->sc_rh,
741 				    SIOP_CTEST5) & CTEST5_BOMASK) << 8;
742 				dbc += (dfifo - (dbc & 0x3ff)) & 0x3ff;
743 			} else {
744 				dbc += (dfifo - (dbc & 0x7f)) & 0x7f;
745 			}
746 		}
747 		sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT0);
748 		if (sstat & SSTAT0_OLF)
749 			dbc++;
750 		if ((sstat & SSTAT0_ORF) && (sc->features & SF_CHIP_DFBC) == 0)
751 			dbc++;
752 		if (siop_cmd->siop_target->flags & TARF_ISWIDE) {
753 			sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh,
754 			    SIOP_SSTAT2);
755 			if (sstat & SSTAT2_OLF1)
756 				dbc++;
757 			if ((sstat & SSTAT2_ORF1) &&
758 			    (sc->features & SF_CHIP_DFBC) == 0)
759 				dbc++;
760 		}
761 		/* clear the FIFO */
762 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
763 		    bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) |
764 		    CTEST3_CLF);
765 	}
766 	table->addr =
767 	    htole32(letoh32(table->addr) + letoh32(table->count) - dbc);
768 	table->count = htole32(dbc);
769 #ifdef DEBUG_DR
770 	printf("now count=%d addr=0x%x\n",
771 	    letoh32(table->count), letoh32(table->addr));
772 #endif
773 }
774 
775 void
776 siop_clearfifo(sc)
777 	struct siop_common_softc *sc;
778 {
779 	int timeout = 0;
780 	int ctest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3);
781 
782 #ifdef DEBUG_INTR
783 	printf("DMA fifo not empty !\n");
784 #endif
785 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
786 	    ctest3 | CTEST3_CLF);
787 	while ((bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) &
788 	    CTEST3_CLF) != 0) {
789 		delay(1);
790 		if (++timeout > 1000) {
791 			printf("clear fifo failed\n");
792 			bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
793 			    bus_space_read_1(sc->sc_rt, sc->sc_rh,
794 			    SIOP_CTEST3) & ~CTEST3_CLF);
795 			return;
796 		}
797 	}
798 }
799 
800 int
801 siop_modechange(sc)
802 	struct siop_common_softc *sc;
803 {
804 	int retry;
805 	int sist0, sist1, stest2;
806 	for (retry = 0; retry < 5; retry++) {
807 		/*
808 		 * datasheet says to wait 100ms and re-read SIST1,
809 		 * to check that DIFFSENSE is stable.
810 		 * We may delay() 5 times for  100ms at interrupt time;
811 		 * hopefully this will not happen often.
812 		 */
813 		delay(100000);
814 		sist0 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST0);
815 		sist1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST1);
816 		if (sist1 & SIEN1_SBMC)
817 			continue; /* we got an irq again */
818 		sc->mode = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST4) &
819 		    STEST4_MODE_MASK;
820 		stest2 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2);
821 		switch(sc->mode) {
822 		case STEST4_MODE_DIF:
823 			printf("%s: switching to differential mode\n",
824 			    sc->sc_dev.dv_xname);
825 			bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2,
826 			    stest2 | STEST2_DIF);
827 			break;
828 		case STEST4_MODE_SE:
829 			printf("%s: switching to single-ended mode\n",
830 			    sc->sc_dev.dv_xname);
831 			bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2,
832 			    stest2 & ~STEST2_DIF);
833 			break;
834 		case STEST4_MODE_LVD:
835 			printf("%s: switching to LVD mode\n",
836 			    sc->sc_dev.dv_xname);
837 			bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2,
838 			    stest2 & ~STEST2_DIF);
839 			break;
840 		default:
841 			printf("%s: invalid SCSI mode 0x%x\n",
842 			    sc->sc_dev.dv_xname, sc->mode);
843 			return 0;
844 		}
845 		return 1;
846 	}
847 	printf("%s: timeout waiting for DIFFSENSE to stabilise\n",
848 	    sc->sc_dev.dv_xname);
849 	return 0;
850 }
851 
852 void
853 siop_resetbus(sc)
854 	struct siop_common_softc *sc;
855 {
856 	int scntl1;
857 	scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1);
858 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1,
859 	    scntl1 | SCNTL1_RST);
860 	/* minimum 25 us, more time won't hurt */
861 	delay(100);
862 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);
863 }
864 
865 void
866 siop_update_xfer_mode(sc, target)
867         struct siop_common_softc *sc;
868         int target;
869 {
870 	struct siop_common_target *siop_target;
871 
872 	siop_target = sc->targets[target];
873 
874 	printf("%s: target %d now using %s%s%d bit ",
875             sc->sc_dev.dv_xname, target,
876 	    (siop_target->flags & TARF_TAG) ? "tagged " : "",
877 	    (siop_target->flags & TARF_ISDT) ? "DT " : "",
878 	    (siop_target->flags & TARF_ISWIDE) ? 16 : 8);
879 
880 	if (siop_target->offset == 0)
881 		printf("async ");
882 	else {
883 		switch (siop_target->period) {
884 		case 9: /*   12.5ns cycle */
885 			printf("80.0");
886 			break;
887 		case 10: /*  25  ns cycle */
888 			printf("40.0");
889 			break;
890 		case 12: /*  48  ns cycle */
891 			printf("20.0");
892 			break;
893 		case 18: /*  72  ns cycle */
894 			printf("13.3");
895 			break;
896 		case 25: /* 100  ns cycle */
897 			printf("10.0");
898 			break;
899 		case 37: /* 118  ns cycle */
900 			printf("6.67");
901 			break;
902 		case 50: /* 200  ns cycle */
903 			printf("5.0");
904 			break;
905 		case 75: /* 300  ns cycle */
906 			printf("3.33");
907 			break;
908 		default:
909 			printf("??");
910 			break;
911 		}
912 		printf(" MHz %d REQ/ACK offset ", siop_target->offset);
913 	}
914 
915 	printf("xfers\n");
916 
917 	if ((sc->features & SF_CHIP_GEBUG) &&
918 	    (siop_target->flags & TARF_ISWIDE) == 0)
919 		/* 1010 workaround: can't do disconnect if not wide, so can't do tag */
920 		siop_target->flags &= ~TARF_TAG;
921 }
922