xref: /openbsd-src/sys/dev/ic/siop_common.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: siop_common.c,v 1.33 2009/02/16 21:19:07 miod Exp $ */
2 /*	$NetBSD: siop_common.c,v 1.37 2005/02/27 00:27:02 perry 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 #define SIOP_NEEDS_PERIOD_TABLES
52 #include <dev/ic/siopreg.h>
53 #include <dev/ic/siopvar_common.h>
54 #include <dev/ic/siopvar.h>
55 
56 #undef DEBUG
57 #undef DEBUG_DR
58 #undef DEBUG_NEG
59 
60 int
61 siop_common_attach(sc)
62 	struct siop_common_softc *sc;
63 {
64 	int error, i;
65 	bus_dma_segment_t seg;
66 	int rseg;
67 
68 	/*
69 	 * Allocate DMA-safe memory for the script and map it.
70 	 */
71 	if ((sc->features & SF_CHIP_RAM) == 0) {
72 		error = bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE,
73 		    PAGE_SIZE, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT);
74 		if (error) {
75 			printf("%s: unable to allocate script DMA memory, "
76 			    "error = %d\n", sc->sc_dev.dv_xname, error);
77 			return error;
78 		}
79 		error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, PAGE_SIZE,
80 		    (caddr_t *)&sc->sc_script,
81 		    BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
82 		if (error) {
83 			printf("%s: unable to map script DMA memory, "
84 			    "error = %d\n", sc->sc_dev.dv_xname, error);
85 			return error;
86 		}
87 		error = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1,
88 		    PAGE_SIZE, 0, BUS_DMA_NOWAIT, &sc->sc_scriptdma);
89 		if (error) {
90 			printf("%s: unable to create script DMA map, "
91 			    "error = %d\n", sc->sc_dev.dv_xname, error);
92 			return error;
93 		}
94 		error = bus_dmamap_load(sc->sc_dmat, sc->sc_scriptdma,
95 		    sc->sc_script, PAGE_SIZE, NULL, BUS_DMA_NOWAIT);
96 		if (error) {
97 			printf("%s: unable to load script DMA map, "
98 			    "error = %d\n", sc->sc_dev.dv_xname, error);
99 			return error;
100 		}
101 		sc->sc_scriptaddr =
102 		    sc->sc_scriptdma->dm_segs[0].ds_addr;
103 		sc->ram_size = PAGE_SIZE;
104 	}
105 
106 	/*
107 	 * sc->sc_link is the template for all device sc_link's
108 	 * for devices attached to this adapter. It is passed to
109 	 * the upper layers in config_found().
110 	 */
111 	sc->sc_link.adapter_softc = sc;
112 	sc->sc_link.adapter_buswidth =
113 	    (sc->features & SF_BUS_WIDE) ? 16 : 8;
114 	sc->sc_link.adapter_target =
115 	    bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCID);
116 	if (sc->sc_link.adapter_target == 0 ||
117 	    sc->sc_link.adapter_target >=
118 	    sc->sc_link.adapter_buswidth)
119 		sc->sc_link.adapter_target = SIOP_DEFAULT_TARGET;
120 
121 	for (i = 0; i < 16; i++)
122 		sc->targets[i] = NULL;
123 
124 	/* find min/max sync period for this chip */
125 	sc->st_maxsync = 0;
126 	sc->dt_maxsync = 0;
127 	sc->st_minsync = 255;
128 	sc->dt_minsync = 255;
129 	for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); i++) {
130 		if (sc->clock_period != scf_period[i].clock)
131 			continue;
132 		if (sc->st_maxsync < scf_period[i].period)
133 			sc->st_maxsync = scf_period[i].period;
134 		if (sc->st_minsync > scf_period[i].period)
135 			sc->st_minsync = scf_period[i].period;
136 	}
137 	if (sc->st_maxsync == 255 || sc->st_minsync == 0)
138 		panic("siop: can't find my sync parameters");
139 	for (i = 0; i < sizeof(dt_scf_period) / sizeof(dt_scf_period[0]); i++) {
140 		if (sc->clock_period != dt_scf_period[i].clock)
141 			continue;
142 		if (sc->dt_maxsync < dt_scf_period[i].period)
143 			sc->dt_maxsync = dt_scf_period[i].period;
144 		if (sc->dt_minsync > dt_scf_period[i].period)
145 			sc->dt_minsync = dt_scf_period[i].period;
146 	}
147 	if (sc->dt_maxsync == 255 || sc->dt_minsync == 0)
148 		panic("siop: can't find my sync parameters");
149 	return 0;
150 }
151 
152 void
153 siop_common_reset(sc)
154 	struct siop_common_softc *sc;
155 {
156 	u_int32_t stest3;
157 
158 	/* reset the chip */
159 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SRST);
160 	delay(1000);
161 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, 0);
162 
163 	/* init registers */
164 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL0,
165 	    SCNTL0_ARB_MASK | SCNTL0_EPC | SCNTL0_AAP);
166 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, 0);
167 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, sc->clock_div);
168 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER, 0);
169 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DIEN, 0xff);
170 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN0,
171 	    0xff & ~(SIEN0_CMP | SIEN0_SEL | SIEN0_RSL));
172 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN1,
173 	    0xff & ~(SIEN1_HTH | SIEN1_GEN));
174 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, 0);
175 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, STEST3_TE);
176 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STIME0,
177 	    (0xb << STIME0_SEL_SHIFT));
178 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCID,
179 	    sc->sc_link.adapter_target | SCID_RRE);
180 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_RESPID0,
181 	    1 << sc->sc_link.adapter_target);
182 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DCNTL,
183 	    (sc->features & SF_CHIP_PF) ? DCNTL_COM | DCNTL_PFEN : DCNTL_COM);
184 	if (sc->features & SF_CHIP_AAIP)
185 		bus_space_write_1(sc->sc_rt, sc->sc_rh,
186 		    SIOP_AIPCNTL1, AIPCNTL1_DIS);
187 
188 	/* enable clock doubler or quadrupler if appropriate */
189 	if (sc->features & (SF_CHIP_DBLR | SF_CHIP_QUAD)) {
190 		stest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3);
191 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1,
192 		    STEST1_DBLEN);
193 		if (sc->features & SF_CHIP_QUAD) {
194 			/* wait for PPL to lock */
195 			while ((bus_space_read_1(sc->sc_rt, sc->sc_rh,
196 			    SIOP_STEST4) & STEST4_LOCK) == 0)
197 				delay(10);
198 		} else {
199 			/* data sheet says 20us - more won't hurt */
200 			delay(100);
201 		}
202 		/* halt scsi clock, select doubler/quad, restart clock */
203 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3,
204 		    stest3 | STEST3_HSC);
205 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1,
206 		    STEST1_DBLEN | STEST1_DBLSEL);
207 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, stest3);
208 	} else {
209 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1, 0);
210 	}
211 	if (sc->features & SF_CHIP_FIFO)
212 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST5,
213 		    bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST5) |
214 		    CTEST5_DFS);
215 	if (sc->features & SF_CHIP_LED0) {
216 		/* Set GPIO0 as output if software LED control is required */
217 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_GPCNTL,
218 		    bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_GPCNTL) & 0xfe);
219 	}
220 	if (sc->features & SF_BUS_ULTRA3) {
221 		/* reset SCNTL4 */
222 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL4, 0);
223 	}
224 	sc->mode = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST4) &
225 	    STEST4_MODE_MASK;
226 
227 	/*
228 	 * initialise the RAM. Without this we may get scsi gross errors on
229 	 * the 1010
230 	 */
231 	if (sc->features & SF_CHIP_RAM)
232 		bus_space_set_region_4(sc->sc_ramt, sc->sc_ramh,
233 			0, 0, sc->ram_size / 4);
234 	sc->sc_reset(sc);
235 }
236 
237 /* prepare tables before sending a cmd */
238 void
239 siop_setuptables(siop_cmd)
240 	struct siop_common_cmd *siop_cmd;
241 {
242 	int i;
243 	struct siop_common_softc *sc = siop_cmd->siop_sc;
244 	struct scsi_xfer *xs = siop_cmd->xs;
245 	int target = xs->sc_link->target;
246 	int lun = xs->sc_link->lun;
247 	int msgoffset = 1;
248 	int *targ_flags = &sc->targets[target]->flags;
249 	int quirks;
250 
251 	siop_cmd->siop_tables->id = siop_htoc32(sc, sc->targets[target]->id);
252 	memset(siop_cmd->siop_tables->msg_out, 0,
253 	    sizeof(siop_cmd->siop_tables->msg_out));
254 	/* request sense doesn't disconnect */
255 	if (siop_cmd->status == CMDST_SENSE)
256 		siop_cmd->siop_tables->msg_out[0] = MSG_IDENTIFY(lun, 0);
257 	else if ((sc->features & SF_CHIP_GEBUG) &&
258 	    (sc->targets[target]->flags & TARF_ISWIDE) == 0)
259 		/*
260 		 * 1010 bug: it seems that the 1010 has problems with reselect
261 		 * when not in wide mode (generate false SCSI gross error).
262 		 * The FreeBSD sym driver has comments about it but their
263 		 * workaround (disable SCSI gross error reporting) doesn't
264 		 * work with my adapter. So disable disconnect when not
265 		 * wide.
266 		 */
267 		siop_cmd->siop_tables->msg_out[0] = MSG_IDENTIFY(lun, 0);
268 	else
269 		siop_cmd->siop_tables->msg_out[0] = MSG_IDENTIFY(lun, 1);
270 	siop_cmd->siop_tables->t_msgout.count = siop_htoc32(sc, msgoffset);
271 	if (sc->targets[target]->status == TARST_ASYNC) {
272 		*targ_flags &= TARF_DT; /* Save TARF_DT 'cuz we don't set it here */
273 		quirks = xs->sc_link->quirks;
274 
275 		if ((quirks & SDEV_NOTAGS) == 0)
276 			*targ_flags |= TARF_TAG;
277 		if (((quirks & SDEV_NOWIDE) == 0) &&
278 		    (sc->features & SF_BUS_WIDE))
279 			*targ_flags |= TARF_WIDE;
280 		if ((quirks & SDEV_NOSYNC) == 0)
281 			*targ_flags |= TARF_SYNC;
282 
283 		if ((sc->features & SF_CHIP_GEBUG) &&
284 		    (*targ_flags & TARF_WIDE) == 0)
285 			/*
286 			 * 1010 workaround: can't do disconnect if not wide,
287 			 * so can't do tag
288 			 */
289 			*targ_flags &= ~TARF_TAG;
290 
291 		/* Safe to call siop_add_dev() multiple times */
292 		siop_add_dev((struct siop_softc *)sc, target, lun);
293 
294 		if ((*targ_flags & TARF_DT) &&
295 		    (sc->mode == STEST4_MODE_LVD)) {
296 			sc->targets[target]->status = TARST_PPR_NEG;
297 			 siop_ppr_msg(siop_cmd, msgoffset, sc->dt_minsync,
298 			    sc->maxoff);
299 		} else if (*targ_flags & TARF_WIDE) {
300 			sc->targets[target]->status = TARST_WIDE_NEG;
301 			siop_wdtr_msg(siop_cmd, msgoffset,
302 			    MSG_EXT_WDTR_BUS_16_BIT);
303 		} else if (*targ_flags & TARF_SYNC) {
304 			sc->targets[target]->status = TARST_SYNC_NEG;
305 			siop_sdtr_msg(siop_cmd, msgoffset, sc->st_minsync,
306 			(sc->maxoff > 31) ? 31 :  sc->maxoff);
307 		} else {
308 			sc->targets[target]->status = TARST_OK;
309 			siop_update_xfer_mode(sc, target);
310 		}
311 	} else if (sc->targets[target]->status == TARST_OK &&
312 	    (*targ_flags & TARF_TAG) &&
313 	    siop_cmd->status != CMDST_SENSE) {
314 		siop_cmd->flags |= CMDFL_TAG;
315 	}
316 	siop_cmd->siop_tables->status =
317 	    siop_htoc32(sc, SCSI_SIOP_NOSTATUS); /* set invalid status */
318 
319 	if ((xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) ||
320 	    siop_cmd->status == CMDST_SENSE) {
321 		bzero(siop_cmd->siop_tables->data,
322 		    sizeof(siop_cmd->siop_tables->data));
323 		for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) {
324 			siop_cmd->siop_tables->data[i].count =
325 			    siop_htoc32(sc,
326 				siop_cmd->dmamap_data->dm_segs[i].ds_len);
327 			siop_cmd->siop_tables->data[i].addr =
328 			    siop_htoc32(sc,
329 				siop_cmd->dmamap_data->dm_segs[i].ds_addr);
330 		}
331 	}
332 }
333 
334 int
335 siop_wdtr_neg(siop_cmd)
336 	struct siop_common_cmd *siop_cmd;
337 {
338 	struct siop_common_softc *sc = siop_cmd->siop_sc;
339 	struct siop_common_target *siop_target = siop_cmd->siop_target;
340 	int target = siop_cmd->xs->sc_link->target;
341 	struct siop_common_xfer *tables = siop_cmd->siop_tables;
342 
343 	if (siop_target->status == TARST_WIDE_NEG) {
344 		/* we initiated wide negotiation */
345 		switch (tables->msg_in[3]) {
346 		case MSG_EXT_WDTR_BUS_8_BIT:
347 			siop_target->flags &= ~TARF_ISWIDE;
348 			sc->targets[target]->id &= ~(SCNTL3_EWS << 24);
349 			break;
350 		case MSG_EXT_WDTR_BUS_16_BIT:
351 			if (siop_target->flags & TARF_WIDE) {
352 				siop_target->flags |= TARF_ISWIDE;
353 				sc->targets[target]->id |= (SCNTL3_EWS << 24);
354 				break;
355 			}
356 		/* FALLTHROUGH */
357 		default:
358 			/*
359  			 * hum, we got more than what we can handle, shouldn't
360 			 * happen. Reject, and stay async
361 			 */
362 			siop_target->flags &= ~TARF_ISWIDE;
363 			siop_target->status = TARST_OK;
364 			siop_target->offset = siop_target->period = 0;
365 			siop_update_xfer_mode(sc, target);
366 			printf("%s: rejecting invalid wide negotiation from "
367 			    "target %d (%d)\n", sc->sc_dev.dv_xname, target,
368 			    tables->msg_in[3]);
369 			tables->t_msgout.count = siop_htoc32(sc, 1);
370 			tables->msg_out[0] = MSG_MESSAGE_REJECT;
371 			return SIOP_NEG_MSGOUT;
372 		}
373 		tables->id = siop_htoc32(sc, sc->targets[target]->id);
374 		bus_space_write_1(sc->sc_rt, sc->sc_rh,
375 		    SIOP_SCNTL3,
376 		    (sc->targets[target]->id >> 24) & 0xff);
377 		/* we now need to do sync */
378 		if (siop_target->flags & TARF_SYNC) {
379 			siop_target->status = TARST_SYNC_NEG;
380 			siop_sdtr_msg(siop_cmd, 0, sc->st_minsync,
381 			    (sc->maxoff > 31) ? 31 : sc->maxoff);
382 			return SIOP_NEG_MSGOUT;
383 		} else {
384 			siop_target->status = TARST_OK;
385 			siop_update_xfer_mode(sc, target);
386 			return SIOP_NEG_ACK;
387 		}
388 	} else {
389 		/* target initiated wide negotiation */
390 		if (tables->msg_in[3] >= MSG_EXT_WDTR_BUS_16_BIT
391 		    && (siop_target->flags & TARF_WIDE)) {
392 			siop_target->flags |= TARF_ISWIDE;
393 			sc->targets[target]->id |= SCNTL3_EWS << 24;
394 		} else {
395 			siop_target->flags &= ~TARF_ISWIDE;
396 			sc->targets[target]->id &= ~(SCNTL3_EWS << 24);
397 		}
398 		tables->id = siop_htoc32(sc, sc->targets[target]->id);
399 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3,
400 		    (sc->targets[target]->id >> 24) & 0xff);
401 		/*
402 		 * we did reset wide parameters, so fall back to async,
403 		 * but don't schedule a sync neg, target should initiate it
404 		 */
405 		siop_target->status = TARST_OK;
406 		siop_target->offset = siop_target->period = 0;
407 		siop_update_xfer_mode(sc, target);
408 		siop_wdtr_msg(siop_cmd, 0, (siop_target->flags & TARF_ISWIDE) ?
409 		    MSG_EXT_WDTR_BUS_16_BIT : MSG_EXT_WDTR_BUS_8_BIT);
410 		return SIOP_NEG_MSGOUT;
411 	}
412 }
413 
414 int
415 siop_ppr_neg(siop_cmd)
416 	struct siop_common_cmd *siop_cmd;
417 {
418 	struct siop_common_softc *sc = siop_cmd->siop_sc;
419 	struct siop_common_target *siop_target = siop_cmd->siop_target;
420 	int target = siop_cmd->xs->sc_link->target;
421 	struct siop_common_xfer *tables = siop_cmd->siop_tables;
422 	int sync, offset, options, scf = 0;
423 	int i;
424 
425 #ifdef DEBUG_NEG
426 	printf("%s: answer on ppr negotiation:", sc->sc_dev.dv_xname);
427 	for (i = 0; i < 8; i++)
428 		printf(" 0x%x", tables->msg_in[i]);
429 	printf("\n");
430 #endif
431 
432 	if (siop_target->status == TARST_PPR_NEG) {
433 		/* we initiated PPR negotiation */
434 		sync = tables->msg_in[3];
435 		offset = tables->msg_in[5];
436 		options = tables->msg_in[7];
437 		if (options != MSG_EXT_PPR_PROT_DT) {
438 			/* should't happen */
439 			printf("%s: ppr negotiation for target %d: "
440 			    "no DT option\n", sc->sc_dev.dv_xname, target);
441 			siop_target->status = TARST_ASYNC;
442 			siop_target->flags &= ~(TARF_DT | TARF_ISDT);
443 			siop_target->offset = 0;
444 			siop_target->period = 0;
445 			goto reject;
446 		}
447 
448 		if (offset > sc->maxoff || sync < sc->dt_minsync ||
449 		    sync > sc->dt_maxsync) {
450 			printf("%s: ppr negotiation for target %d: "
451 			    "offset (%d) or sync (%d) out of range\n",
452 			    sc->sc_dev.dv_xname, target, offset, sync);
453 			/* should not happen */
454 			siop_target->status = TARST_ASYNC;
455 			siop_target->flags &= ~(TARF_DT | TARF_ISDT);
456 			siop_target->offset = 0;
457 			siop_target->period = 0;
458 			goto reject;
459 		} else {
460 			for (i = 0; i <
461 			    sizeof(dt_scf_period) / sizeof(dt_scf_period[0]);
462 			    i++) {
463 				if (sc->clock_period != dt_scf_period[i].clock)
464 					continue;
465 				if (dt_scf_period[i].period == sync) {
466 					/* ok, found it. we now are sync. */
467 					siop_target->offset = offset;
468 					siop_target->period = sync;
469 					scf = dt_scf_period[i].scf;
470 					siop_target->flags |= TARF_ISDT;
471 				}
472 			}
473 			if ((siop_target->flags & TARF_ISDT) == 0) {
474 				printf("%s: ppr negotiation for target %d: "
475 				    "sync (%d) incompatible with adapter\n",
476 				    sc->sc_dev.dv_xname, target, sync);
477 				/*
478 				 * we didn't find it in our table, do async
479 				 * send reject msg, start SDTR/WDTR neg
480 				 */
481 				siop_target->status = TARST_ASYNC;
482 				siop_target->flags &= ~(TARF_DT | TARF_ISDT);
483 				siop_target->offset = 0;
484 				siop_target->period = 0;
485 				goto reject;
486 			}
487 		}
488 		if (tables->msg_in[6] != 1) {
489 			printf("%s: ppr negotiation for target %d: "
490 			    "transfer width (%d) incompatible with dt\n",
491 			    sc->sc_dev.dv_xname, target, tables->msg_in[6]);
492 			/* DT mode can only be done with wide transfers */
493 			siop_target->status = TARST_ASYNC;
494 			siop_target->flags &= ~(TARF_DT | TARF_ISDT);
495 			siop_target->offset = 0;
496 			siop_target->period = 0;
497 			goto reject;
498 		}
499 		siop_target->flags |= TARF_ISWIDE;
500 		sc->targets[target]->id |= (SCNTL3_EWS << 24);
501 		sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24);
502 		sc->targets[target]->id |= scf << (24 + SCNTL3_SCF_SHIFT);
503 		sc->targets[target]->id &= ~(SXFER_MO_MASK << 8);
504 		sc->targets[target]->id |=
505 		    (siop_target->offset & SXFER_MO_MASK) << 8;
506 		sc->targets[target]->id &= ~0xff;
507 		sc->targets[target]->id |= SCNTL4_U3EN;
508 		siop_target->status = TARST_OK;
509 		siop_update_xfer_mode(sc, target);
510 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3,
511 		    (sc->targets[target]->id >> 24) & 0xff);
512 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER,
513 		    (sc->targets[target]->id >> 8) & 0xff);
514 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL4,
515 		    sc->targets[target]->id & 0xff);
516 		return SIOP_NEG_ACK;
517 	} else {
518 		/* target initiated PPR negotiation, shouldn't happen */
519 		printf("%s: rejecting invalid PPR negotiation from "
520 		    "target %d\n", sc->sc_dev.dv_xname, target);
521 reject:
522 		tables->t_msgout.count = siop_htoc32(sc, 1);
523 		tables->msg_out[0] = MSG_MESSAGE_REJECT;
524 		return SIOP_NEG_MSGOUT;
525 	}
526 }
527 
528 int
529 siop_sdtr_neg(siop_cmd)
530 	struct siop_common_cmd *siop_cmd;
531 {
532 	struct siop_common_softc *sc = siop_cmd->siop_sc;
533 	struct siop_common_target *siop_target = siop_cmd->siop_target;
534 	int target = siop_cmd->xs->sc_link->target;
535 	int sync, maxoffset, offset, i;
536 	int send_msgout = 0;
537 	struct siop_common_xfer *tables = siop_cmd->siop_tables;
538 
539 	/* limit to Ultra/2 parameters, need PPR for Ultra/3 */
540 	maxoffset = (sc->maxoff > 31) ? 31 : sc->maxoff;
541 
542 	sync = tables->msg_in[3];
543 	offset = tables->msg_in[4];
544 
545 	if (siop_target->status == TARST_SYNC_NEG) {
546 		/* we initiated sync negotiation */
547 		siop_target->status = TARST_OK;
548 #ifdef DEBUG
549 		printf("sdtr: sync %d offset %d\n", sync, offset);
550 #endif
551 		if (offset > maxoffset || sync < sc->st_minsync ||
552 			sync > sc->st_maxsync)
553 			goto reject;
554 		for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]);
555 		    i++) {
556 			if (sc->clock_period != scf_period[i].clock)
557 				continue;
558 			if (scf_period[i].period == sync) {
559 				/* ok, found it. we now are sync. */
560 				siop_target->offset = offset;
561 				siop_target->period = sync;
562 				sc->targets[target]->id &=
563 				    ~(SCNTL3_SCF_MASK << 24);
564 				sc->targets[target]->id |= scf_period[i].scf
565 				    << (24 + SCNTL3_SCF_SHIFT);
566 				if (sync < 25 && /* Ultra */
567 				    (sc->features & SF_BUS_ULTRA3) == 0)
568 					sc->targets[target]->id |=
569 					    SCNTL3_ULTRA << 24;
570 				else
571 					sc->targets[target]->id &=
572 					    ~(SCNTL3_ULTRA << 24);
573 				sc->targets[target]->id &=
574 				    ~(SXFER_MO_MASK << 8);
575 				sc->targets[target]->id |=
576 				    (offset & SXFER_MO_MASK) << 8;
577 				sc->targets[target]->id &= ~0xff; /* scntl4 */
578 				goto end;
579 			}
580 		}
581 		/*
582 		 * we didn't find it in our table, do async and send reject
583 		 * msg
584 		 */
585 reject:
586 		send_msgout = 1;
587 		tables->t_msgout.count = siop_htoc32(sc, 1);
588 		tables->msg_out[0] = MSG_MESSAGE_REJECT;
589 		sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24);
590 		sc->targets[target]->id &= ~(SCNTL3_ULTRA << 24);
591 		sc->targets[target]->id &= ~(SXFER_MO_MASK << 8);
592 		sc->targets[target]->id &= ~0xff; /* scntl4 */
593 		siop_target->offset = siop_target->period = 0;
594 	} else { /* target initiated sync neg */
595 #ifdef DEBUG
596 		printf("sdtr (target): sync %d offset %d\n", sync, offset);
597 #endif
598 		if (offset == 0 || sync > sc->st_maxsync) { /* async */
599 			goto async;
600 		}
601 		if (offset > maxoffset)
602 			offset = maxoffset;
603 		if (sync < sc->st_minsync)
604 			sync = sc->st_minsync;
605 		/* look for sync period */
606 		for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]);
607 		    i++) {
608 			if (sc->clock_period != scf_period[i].clock)
609 				continue;
610 			if (scf_period[i].period == sync) {
611 				/* ok, found it. we now are sync. */
612 				siop_target->offset = offset;
613 				siop_target->period = sync;
614 				sc->targets[target]->id &=
615 				    ~(SCNTL3_SCF_MASK << 24);
616 				sc->targets[target]->id |= scf_period[i].scf
617 				    << (24 + SCNTL3_SCF_SHIFT);
618 				if (sync < 25 && /* Ultra */
619 				    (sc->features & SF_BUS_ULTRA3) == 0)
620 					sc->targets[target]->id |=
621 					    SCNTL3_ULTRA << 24;
622 				else
623 					sc->targets[target]->id &=
624 					    ~(SCNTL3_ULTRA << 24);
625 				sc->targets[target]->id &=
626 				    ~(SXFER_MO_MASK << 8);
627 				sc->targets[target]->id |=
628 				    (offset & SXFER_MO_MASK) << 8;
629 				sc->targets[target]->id &= ~0xff; /* scntl4 */
630 				siop_sdtr_msg(siop_cmd, 0, sync, offset);
631 				send_msgout = 1;
632 				goto end;
633 			}
634 		}
635 async:
636 		siop_target->offset = siop_target->period = 0;
637 		sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24);
638 		sc->targets[target]->id &= ~(SCNTL3_ULTRA << 24);
639 		sc->targets[target]->id &= ~(SXFER_MO_MASK << 8);
640 		sc->targets[target]->id &= ~0xff; /* scntl4 */
641 		siop_sdtr_msg(siop_cmd, 0, 0, 0);
642 		send_msgout = 1;
643 	}
644 end:
645 	if (siop_target->status == TARST_OK)
646 		siop_update_xfer_mode(sc, target);
647 #ifdef DEBUG
648 	printf("id now 0x%x\n", sc->targets[target]->id);
649 #endif
650 	tables->id = siop_htoc32(sc, sc->targets[target]->id);
651 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3,
652 	    (sc->targets[target]->id >> 24) & 0xff);
653 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER,
654 	    (sc->targets[target]->id >> 8) & 0xff);
655 	if (send_msgout) {
656 		return SIOP_NEG_MSGOUT;
657 	} else {
658 		return SIOP_NEG_ACK;
659 	}
660 }
661 
662 void
663 siop_sdtr_msg(siop_cmd, offset, ssync, soff)
664 	struct siop_common_cmd *siop_cmd;
665 	int offset;
666 	int ssync, soff;
667 {
668 	siop_cmd->siop_tables->msg_out[offset + 0] = MSG_EXTENDED;
669 	siop_cmd->siop_tables->msg_out[offset + 1] = MSG_EXT_SDTR_LEN;
670 	siop_cmd->siop_tables->msg_out[offset + 2] = MSG_EXT_SDTR;
671 	siop_cmd->siop_tables->msg_out[offset + 3] = ssync;
672 	siop_cmd->siop_tables->msg_out[offset + 4] = soff;
673 	siop_cmd->siop_tables->t_msgout.count =
674 	    siop_htoc32(siop_cmd->siop_sc, offset + MSG_EXT_SDTR_LEN + 2);
675 }
676 
677 void
678 siop_wdtr_msg(siop_cmd, offset, wide)
679 	struct siop_common_cmd *siop_cmd;
680 	int offset;
681 	int wide;
682 {
683 	siop_cmd->siop_tables->msg_out[offset + 0] = MSG_EXTENDED;
684 	siop_cmd->siop_tables->msg_out[offset + 1] = MSG_EXT_WDTR_LEN;
685 	siop_cmd->siop_tables->msg_out[offset + 2] = MSG_EXT_WDTR;
686 	siop_cmd->siop_tables->msg_out[offset + 3] = wide;
687 	siop_cmd->siop_tables->t_msgout.count =
688 	    siop_htoc32(siop_cmd->siop_sc, offset + MSG_EXT_WDTR_LEN + 2);
689 }
690 
691 void
692 siop_ppr_msg(siop_cmd, offset, ssync, soff)
693 	struct siop_common_cmd *siop_cmd;
694 	int offset;
695 	int ssync, soff;
696 {
697 	siop_cmd->siop_tables->msg_out[offset + 0] = MSG_EXTENDED;
698 	siop_cmd->siop_tables->msg_out[offset + 1] = MSG_EXT_PPR_LEN;
699 	siop_cmd->siop_tables->msg_out[offset + 2] = MSG_EXT_PPR;
700 	siop_cmd->siop_tables->msg_out[offset + 3] = ssync;
701 	siop_cmd->siop_tables->msg_out[offset + 4] = 0; /* reserved */
702 	siop_cmd->siop_tables->msg_out[offset + 5] = soff;
703 	siop_cmd->siop_tables->msg_out[offset + 6] = 1; /* wide */
704 	siop_cmd->siop_tables->msg_out[offset + 7] = MSG_EXT_PPR_PROT_DT;
705 	siop_cmd->siop_tables->t_msgout.count =
706 	    siop_htoc32(siop_cmd->siop_sc, offset + MSG_EXT_PPR_LEN + 2);
707 }
708 
709 void
710 siop_minphys(struct buf *bp, struct scsi_link *sl)
711 {
712 	if (bp->b_bcount > SIOP_MAXFER)
713 		bp->b_bcount = SIOP_MAXFER;
714 
715 	minphys(bp);
716 }
717 
718 void
719 siop_ma(siop_cmd)
720 	struct siop_common_cmd *siop_cmd;
721 {
722 	int offset, dbc, sstat;
723 	struct siop_common_softc *sc = siop_cmd->siop_sc;
724 	scr_table_t *table; /* table with partial xfer */
725 
726 	/*
727 	 * compute how much of the current table didn't get handled when
728 	 * a phase mismatch occurs
729 	 */
730 	if ((siop_cmd->xs->flags & (SCSI_DATA_OUT | SCSI_DATA_IN))
731 	    == 0)
732 	    return; /* no valid data transfer */
733 
734 	offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA + 1);
735 	if (offset >= SIOP_NSG) {
736 		printf("%s: bad offset in siop_sdp (%d)\n",
737 		    sc->sc_dev.dv_xname, offset);
738 		return;
739 	}
740 	table = &siop_cmd->siop_tables->data[offset];
741 #ifdef DEBUG_DR
742 	printf("siop_ma: offset %d count=%d addr=0x%x ", offset,
743 	    table->count, table->addr);
744 #endif
745 	dbc = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DBC) & 0x00ffffff;
746 	if (siop_cmd->xs->flags & SCSI_DATA_OUT) {
747 		if (sc->features & SF_CHIP_DFBC) {
748 			dbc +=
749 			    bus_space_read_2(sc->sc_rt, sc->sc_rh, SIOP_DFBC);
750 		} else {
751 			/* need to account stale data in FIFO */
752 			int dfifo =
753 			    bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DFIFO);
754 			if (sc->features & SF_CHIP_FIFO) {
755 				dfifo |= (bus_space_read_1(sc->sc_rt, sc->sc_rh,
756 				    SIOP_CTEST5) & CTEST5_BOMASK) << 8;
757 				dbc += (dfifo - (dbc & 0x3ff)) & 0x3ff;
758 			} else {
759 				dbc += (dfifo - (dbc & 0x7f)) & 0x7f;
760 			}
761 		}
762 		sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT0);
763 		if (sstat & SSTAT0_OLF)
764 			dbc++;
765 		if ((sstat & SSTAT0_ORF) && (sc->features & SF_CHIP_DFBC) == 0)
766 			dbc++;
767 		if (siop_cmd->siop_target->flags & TARF_ISWIDE) {
768 			sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh,
769 			    SIOP_SSTAT2);
770 			if (sstat & SSTAT2_OLF1)
771 				dbc++;
772 			if ((sstat & SSTAT2_ORF1) &&
773 			    (sc->features & SF_CHIP_DFBC) == 0)
774 				dbc++;
775 		}
776 		/* clear the FIFO */
777 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
778 		    bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) |
779 		    CTEST3_CLF);
780 	}
781 	siop_cmd->flags |= CMDFL_RESID;
782 	siop_cmd->resid = dbc;
783 }
784 
785 void
786 siop_sdp(siop_cmd, offset)
787 	struct siop_common_cmd *siop_cmd;
788 	int offset;
789 {
790 	struct siop_common_softc *sc = siop_cmd->siop_sc;
791 	scr_table_t *table;
792 
793 	if ((siop_cmd->xs->flags & (SCSI_DATA_OUT | SCSI_DATA_IN))
794 	    == 0)
795 	    return; /* no data pointers to save */
796 
797 	/*
798 	 * offset == SIOP_NSG may be a valid condition if we get a Save data
799 	 * pointer when the xfer is done. Just ignore the Save data pointer
800 	 * in this case
801 	 */
802 	if (offset == SIOP_NSG)
803 		return;
804 #ifdef DIAGNOSTIC
805 	if (offset > SIOP_NSG) {
806 		sc_print_addr(siop_cmd->xs->sc_link);
807 		printf("offset %d > %d\n", offset, SIOP_NSG);
808 		panic("siop_sdp: offset");
809 	}
810 #endif
811 	/*
812 	 * Save data pointer. We do this by adjusting the tables to point
813 	 * at the beginning of the data not yet transfered.
814 	 * offset points to the first table with untransfered data.
815 	 */
816 
817 	/*
818 	 * before doing that we decrease resid from the amount of data which
819 	 * has been transfered.
820 	 */
821 	siop_update_resid(siop_cmd, offset);
822 
823 	/*
824 	 * First let see if we have a resid from a phase mismatch. If so,
825 	 * we have to adjst the table at offset to remove transfered data.
826 	 */
827 	if (siop_cmd->flags & CMDFL_RESID) {
828 		siop_cmd->flags &= ~CMDFL_RESID;
829 		table = &siop_cmd->siop_tables->data[offset];
830 		/* "cut" already transfered data from this table */
831 		table->addr =
832 		    siop_htoc32(sc, siop_ctoh32(sc, table->addr) +
833 		    siop_ctoh32(sc, table->count) - siop_cmd->resid);
834 		table->count = siop_htoc32(sc, siop_cmd->resid);
835 	}
836 
837 	/*
838 	 * now we can remove entries which have been transfered.
839 	 * We just move the entries with data left at the beginning of the
840 	 * tables
841 	 */
842 	bcopy(&siop_cmd->siop_tables->data[offset],
843 	    &siop_cmd->siop_tables->data[0],
844 	    (SIOP_NSG - offset) * sizeof(scr_table_t));
845 }
846 
847 void
848 siop_update_resid(siop_cmd, offset)
849 	struct siop_common_cmd *siop_cmd;
850 	int offset;
851 {
852 	struct siop_common_softc *sc = siop_cmd->siop_sc;
853 	scr_table_t *table;
854 	int i;
855 
856 	if ((siop_cmd->xs->flags & (SCSI_DATA_OUT | SCSI_DATA_IN))
857 	    == 0)
858 	    return; /* no data to transfer */
859 
860 	/*
861 	 * update resid. First account for the table entries which have
862 	 * been fully completed.
863 	 */
864 	for (i = 0; i < offset; i++)
865 		siop_cmd->xs->resid -=
866 		    siop_ctoh32(sc, siop_cmd->siop_tables->data[i].count);
867 	/*
868 	 * if CMDFL_RESID is set, the last table (pointed by offset) is a
869 	 * partial transfers. If not, offset points to the entry folloing
870 	 * the last full transfer.
871 	 */
872 	if (siop_cmd->flags & CMDFL_RESID) {
873 		table = &siop_cmd->siop_tables->data[offset];
874 		siop_cmd->xs->resid -=
875 		    siop_ctoh32(sc, table->count) - siop_cmd->resid;
876 	}
877 }
878 
879 int
880 siop_iwr(siop_cmd)
881 	struct siop_common_cmd *siop_cmd;
882 {
883 	int offset;
884 	scr_table_t *table; /* table with IWR */
885 	struct siop_common_softc *sc = siop_cmd->siop_sc;
886 	/* handle ignore wide residue messages */
887 
888 	/* if target isn't wide, reject */
889 	if ((siop_cmd->siop_target->flags & TARF_ISWIDE) == 0) {
890 		siop_cmd->siop_tables->t_msgout.count = siop_htoc32(sc, 1);
891 		siop_cmd->siop_tables->msg_out[0] = MSG_MESSAGE_REJECT;
892 		return SIOP_NEG_MSGOUT;
893 	}
894 	/* get index of current command in table */
895 	offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA + 1);
896 	/*
897 	 * if the current table did complete, we're now pointing at the
898 	 * next one. Go back one if we didn't see a phase mismatch.
899 	 */
900 	if ((siop_cmd->flags & CMDFL_RESID) == 0)
901 		offset--;
902 	table = &siop_cmd->siop_tables->data[offset];
903 
904 	if ((siop_cmd->flags & CMDFL_RESID) == 0) {
905 		if (siop_ctoh32(sc, table->count) & 1) {
906 			/* we really got the number of bytes we expected */
907 			return SIOP_NEG_ACK;
908 		} else {
909 			/*
910 			 * now we really had a short xfer, by one byte.
911 			 * handle it just as if we had a phase mistmatch
912 			 * (there is a resid of one for this table).
913 			 * Update scratcha1 to reflect the fact that
914 			 * this xfer isn't complete.
915 			 */
916 			 siop_cmd->flags |= CMDFL_RESID;
917 			 siop_cmd->resid = 1;
918 			 bus_space_write_1(sc->sc_rt, sc->sc_rh,
919 			     SIOP_SCRATCHA + 1, offset);
920 			 return SIOP_NEG_ACK;
921 		}
922 	} else {
923 		/*
924 		 * we already have a short xfer for this table; it's
925 		 * just one byte less than we though it was
926 		 */
927 		siop_cmd->resid--;
928 		return SIOP_NEG_ACK;
929 	}
930 }
931 
932 void
933 siop_clearfifo(sc)
934 	struct siop_common_softc *sc;
935 {
936 	int timeout = 0;
937 	int ctest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3);
938 
939 #ifdef DEBUG_INTR
940 	printf("DMA fifo not empty !\n");
941 #endif
942 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
943 	    ctest3 | CTEST3_CLF);
944 	while ((bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) &
945 	    CTEST3_CLF) != 0) {
946 		delay(1);
947 		if (++timeout > 1000) {
948 			printf("clear fifo failed\n");
949 			bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
950 			    bus_space_read_1(sc->sc_rt, sc->sc_rh,
951 			    SIOP_CTEST3) & ~CTEST3_CLF);
952 			return;
953 		}
954 	}
955 }
956 
957 int
958 siop_modechange(sc)
959 	struct siop_common_softc *sc;
960 {
961 	int retry;
962 	int sist0, sist1, stest2;
963 	for (retry = 0; retry < 5; retry++) {
964 		/*
965 		 * datasheet says to wait 100ms and re-read SIST1,
966 		 * to check that DIFFSENSE is stable.
967 		 * We may delay() 5 times for  100ms at interrupt time;
968 		 * hopefully this will not happen often.
969 		 */
970 		delay(100000);
971 		sist0 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST0);
972 		sist1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST1);
973 		if (sist1 & SIEN1_SBMC)
974 			continue; /* we got an irq again */
975 		sc->mode = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST4) &
976 		    STEST4_MODE_MASK;
977 		stest2 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2);
978 		switch(sc->mode) {
979 		case STEST4_MODE_DIF:
980 			printf("%s: switching to differential mode\n",
981 			    sc->sc_dev.dv_xname);
982 			bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2,
983 			    stest2 | STEST2_DIF);
984 			break;
985 		case STEST4_MODE_SE:
986 			printf("%s: switching to single-ended mode\n",
987 			    sc->sc_dev.dv_xname);
988 			bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2,
989 			    stest2 & ~STEST2_DIF);
990 			break;
991 		case STEST4_MODE_LVD:
992 			printf("%s: switching to LVD mode\n",
993 			    sc->sc_dev.dv_xname);
994 			bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2,
995 			    stest2 & ~STEST2_DIF);
996 			break;
997 		default:
998 			printf("%s: invalid SCSI mode 0x%x\n",
999 			    sc->sc_dev.dv_xname, sc->mode);
1000 			return 0;
1001 		}
1002 		return 1;
1003 	}
1004 	printf("%s: timeout waiting for DIFFSENSE to stabilise\n",
1005 	    sc->sc_dev.dv_xname);
1006 	return 0;
1007 }
1008 
1009 void
1010 siop_resetbus(sc)
1011 	struct siop_common_softc *sc;
1012 {
1013 	int scntl1;
1014 	scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1);
1015 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1,
1016 	    scntl1 | SCNTL1_RST);
1017 	/* minimum 25 us, more time won't hurt */
1018 	delay(100);
1019 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);
1020 }
1021 
1022 void
1023 siop_update_xfer_mode(sc, target)
1024         struct siop_common_softc *sc;
1025         int target;
1026 {
1027 	struct siop_common_target *siop_target;
1028 
1029 	siop_target = sc->targets[target];
1030 
1031 	printf("%s: target %d now using %s%s%d bit ",
1032             sc->sc_dev.dv_xname, target,
1033 	    (siop_target->flags & TARF_TAG) ? "tagged " : "",
1034 	    (siop_target->flags & TARF_ISDT) ? "DT " : "",
1035 	    (siop_target->flags & TARF_ISWIDE) ? 16 : 8);
1036 
1037 	if (siop_target->offset == 0)
1038 		printf("async ");
1039 	else {
1040 		switch (siop_target->period) {
1041 		case 9: /*   12.5ns cycle */
1042 			printf("80.0");
1043 			break;
1044 		case 10: /*  25  ns cycle */
1045 			printf("40.0");
1046 			break;
1047 		case 12: /*  48  ns cycle */
1048 			printf("20.0");
1049 			break;
1050 		case 18: /*  72  ns cycle */
1051 			printf("13.3");
1052 			break;
1053 		case 25: /* 100  ns cycle */
1054 			printf("10.0");
1055 			break;
1056 		case 37: /* 118  ns cycle */
1057 			printf("6.67");
1058 			break;
1059 		case 50: /* 200  ns cycle */
1060 			printf("5.0");
1061 			break;
1062 		case 75: /* 300  ns cycle */
1063 			printf("3.33");
1064 			break;
1065 		default:
1066 			printf("??");
1067 			break;
1068 		}
1069 		printf(" MHz %d REQ/ACK offset ", siop_target->offset);
1070 	}
1071 
1072 	printf("xfers\n");
1073 
1074 	if ((sc->features & SF_CHIP_GEBUG) &&
1075 	    (siop_target->flags & TARF_ISWIDE) == 0)
1076 		/* 1010 workaround: can't do disconnect if not wide, so can't do tag */
1077 		siop_target->flags &= ~TARF_TAG;
1078 }
1079