xref: /openbsd/sys/dev/ic/siop_common.c (revision d485f761)
1 /*	$OpenBSD: siop_common.c,v 1.12 2001/10/30 00:02:55 krw Exp $ */
2 /*	$NetBSD: siop_common.c,v 1.12 2001/02/11 18:04:50 bouyer Exp $	*/
3 
4 /*
5  * Copyright (c) 2000 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.h>
53 #include <dev/ic/siopvar_common.h>
54 
55 #undef DEBUG
56 #undef DEBUG_DR
57 
58 int siop_find_lun0_quirks __P((struct siop_softc *, u_int8_t, u_int16_t));
59 
60 void
61 siop_common_reset(sc)
62 	struct siop_softc *sc;
63 {
64 	u_int32_t stest3;
65 
66 	/* reset the chip */
67 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SRST);
68 	delay(1000);
69 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, 0);
70 
71 	/* init registers */
72 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL0,
73 	    SCNTL0_ARB_MASK | SCNTL0_EPC | SCNTL0_AAP);
74 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, 0);
75 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, sc->clock_div);
76 	if (sc->features & SF_CHIP_C10)
77 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL4, 0);
78 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER, 0);
79 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DIEN, 0xff);
80 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN0,
81 	    0xff & ~(SIEN0_CMP | SIEN0_SEL | SIEN0_RSL));
82 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN1,
83 	    0xff & ~(SIEN1_HTH | SIEN1_GEN));
84 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, 0);
85 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, STEST3_TE);
86 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STIME0,
87 	    (0xb << STIME0_SEL_SHIFT));
88 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCID,
89 	    sc->sc_link.adapter_target | SCID_RRE);
90 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_RESPID0,
91 	    1 << sc->sc_link.adapter_target);
92 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DCNTL,
93 	    (sc->features & SF_CHIP_PF) ? DCNTL_COM | DCNTL_PFEN : DCNTL_COM);
94 
95 	/* enable clock doubler or quadruler if appropriate */
96 	if (sc->features & (SF_CHIP_DBLR | SF_CHIP_QUAD)) {
97 		stest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3);
98 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1,
99 		    STEST1_DBLEN);
100 		if ((sc->features & (SF_CHIP_QUAD | SF_CHIP_C10)) == SF_CHIP_QUAD) {
101 			/* wait for PPL to lock */
102 			while ((bus_space_read_1(sc->sc_rt, sc->sc_rh,
103 			    SIOP_STEST4) & STEST4_LOCK) == 0)
104 				delay(10);
105 		} else {
106 			/* data sheet says 20us - more won't hurt */
107 			delay(100);
108 		}
109 		/* halt scsi clock, select doubler/quad, restart clock */
110 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3,
111 		    stest3 | STEST3_HSC);
112 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1,
113 		    STEST1_DBLEN | STEST1_DBLSEL);
114 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, stest3);
115 	} else {
116 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1, 0);
117 	}
118 	if (sc->features & SF_CHIP_FIFO)
119 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST5,
120 		    bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST5) |
121 		    CTEST5_DFS);
122 
123 	sc->sc_reset(sc);
124 }
125 
126 int
127 siop_find_lun0_quirks(sc, bus, target)
128 	struct siop_softc *sc;
129 	u_int8_t bus;
130 	u_int16_t target;
131 {
132 	struct scsi_link *sc_link;
133 	struct device *dev;
134 
135 	for (dev = TAILQ_FIRST(&alldevs); dev != NULL; dev = TAILQ_NEXT(dev, dv_list))
136 		if (dev->dv_parent == (struct device *)sc) {
137 			sc_link = ((struct scsibus_softc *)dev)->sc_link[target][0];
138 			if ((sc_link != NULL) && (sc_link->scsibus == bus))
139 				return sc_link->quirks;
140 		}
141 
142 	/* If we can't find a quirks entry, assume the worst */
143 	return (SDEV_NOTAGS | SDEV_NOWIDE | SDEV_NOSYNC);
144 }
145 
146 /* prepare tables before sending a cmd */
147 void
148 siop_setuptables(siop_cmd)
149 	struct siop_cmd *siop_cmd;
150 {
151 	int i;
152 	struct siop_softc *sc = siop_cmd->siop_sc;
153 	struct scsi_xfer *xs = siop_cmd->xs;
154 	int target = xs->sc_link->target;
155 	int lun = xs->sc_link->lun;
156 	int *targ_flags = &sc->targets[target]->flags;
157 	int quirks;
158 
159 	siop_cmd->siop_tables.id = htole32(sc->targets[target]->id);
160 	memset(siop_cmd->siop_tables.msg_out, 0, 8);
161 	if (siop_cmd->status != CMDST_SENSE)
162 		siop_cmd->siop_tables.msg_out[0] = MSG_IDENTIFY(lun, 1);
163 	else
164 		siop_cmd->siop_tables.msg_out[0] = MSG_IDENTIFY(lun, 0);
165 	siop_cmd->siop_tables.t_msgout.count= htole32(1);
166 	if (sc->targets[target]->status == TARST_ASYNC) {
167 		*targ_flags = 0;
168 		if (lun == 0)
169 			quirks = xs->sc_link->quirks;
170 		else
171 			quirks = siop_find_lun0_quirks(sc, xs->sc_link->scsibus, target);
172 
173 		if ((quirks & SDEV_NOTAGS) == 0) {
174 			*targ_flags |= TARF_TAG;
175 			xs->sc_link->openings += SIOP_NTAG - SIOP_OPENINGS;
176 		}
177 		if ((quirks & SDEV_NOWIDE) == 0)
178 			*targ_flags |= TARF_WIDE;
179 		if ((quirks & SDEV_NOSYNC) == 0)
180 			*targ_flags |= TARF_SYNC;
181 
182 		/* Safe to call siop_add_dev() multiple times */
183 		siop_add_dev(sc, target, 0);
184 
185 		if ((sc->features & SF_CHIP_C10)
186 		    && (*targ_flags & TARF_WIDE)
187 		    && (xs->sc_link->inquiry_flags2 & (SID_CLOCKING | SID_QAS | SID_IUS))) {
188 			sc->targets[target]->status = TARST_PPR_NEG;
189 			siop_ppr_msg(siop_cmd, 1,
190 				     (sc->min_dt_sync == 0) ? sc->min_st_sync : sc->min_dt_sync,
191 				     sc->maxoff);
192 		} else if (*targ_flags & TARF_WIDE) {
193 			sc->targets[target]->status = TARST_WIDE_NEG;
194 			siop_wdtr_msg(siop_cmd, 1, MSG_EXT_WDTR_BUS_16_BIT);
195 		} else if (*targ_flags & TARF_SYNC) {
196 			sc->targets[target]->status = TARST_SYNC_NEG;
197 			siop_sdtr_msg(siop_cmd, 1, sc->min_st_sync, sc->maxoff);
198 		} else {
199 			sc->targets[target]->status = TARST_OK;
200 			siop_print_info(sc, target);
201 		}
202 	} else if (sc->targets[target]->status == TARST_OK &&
203 	    (*targ_flags & TARF_TAG) &&
204 	    siop_cmd->status != CMDST_SENSE) {
205 		siop_cmd->flags |= CMDFL_TAG;
206 	}
207 	siop_cmd->siop_tables.status =
208 	    htole32(SCSI_SIOP_NOSTATUS); /* set invalid status */
209 
210 	siop_cmd->siop_tables.cmd.count =
211 	    htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_len);
212 	siop_cmd->siop_tables.cmd.addr =
213 	    htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_addr);
214 	if ((xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) ||
215 	    siop_cmd->status == CMDST_SENSE) {
216 		for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) {
217 			siop_cmd->siop_tables.data[i].count =
218 			    htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len);
219 			siop_cmd->siop_tables.data[i].addr =
220 			    htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr);
221 		}
222 	}
223 	siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
224 }
225 
226 int
227 siop_ppr_neg(siop_cmd)
228 	struct siop_cmd *siop_cmd;
229 {
230 	struct siop_softc *sc = siop_cmd->siop_sc;
231 	struct siop_target *siop_target = siop_cmd->siop_target;
232 	int target = siop_cmd->xs->sc_link->target;
233 	struct siop_xfer_common *tables = &siop_cmd->siop_xfer->tables;
234 	int offset, sync, protocol, scf;
235 
236 	sync     = tables->msg_in[3];
237 	offset   = tables->msg_in[5];
238 	protocol = tables->msg_in[7];
239 
240 #ifdef DEBUG
241 	printf("%s: siop_ppr_neg: sync = %x, offset = %x, protocol = %x\n",
242 	    sc->sc_dev.dv_xname, sync, offset, protocol);
243 #endif
244 	/*
245 	 * Process protocol bits first, because finding the correct scf
246 	 * via siop_period_factor_to_scf() requires the TARF_ISDT flag
247 	 * to be correctly set.
248 	 */
249 	if (protocol & MSG_EXT_PPR_PROT_IUS)
250 		siop_target->flags |= TARF_ISIUS;
251 
252 	if (protocol & MSG_EXT_PPR_PROT_DT) {
253 		siop_target->flags |= TARF_ISDT;
254 		sc->targets[target]->id |= SCNTL4_ULTRA3;
255 	}
256 
257 	if (protocol & MSG_EXT_PPR_PROT_QAS)
258 		siop_target->flags |= TARF_ISQAS;
259 
260 	scf = siop_period_factor_to_scf(sc, sync, siop_target->flags);
261 
262 	if ((offset > sc->maxoff) ||
263 	    (scf == 0) ||
264 	    ((siop_target->flags & TARF_ISDT) && (offset == 1))) {
265 		tables->t_msgout.count= htole32(1);
266 		tables->msg_out[0] = MSG_MESSAGE_REJECT;
267 		return (SIOP_NEG_MSGOUT);
268 	}
269 
270 	siop_target->id |= scf << (24 + SCNTL3_SCF_SHIFT);
271 
272 	if (((sc->features & SF_CHIP_C10) == 0) && (sync < 25))
273 		siop_target->id |= SCNTL3_ULTRA << 24;
274 
275 	siop_target->id |= (offset & 0xff) << 8;
276 
277 	if (tables->msg_in[6] == MSG_EXT_WDTR_BUS_16_BIT) {
278 		siop_target->flags |= TARF_ISWIDE;
279 		sc->targets[target]->id |= (SCNTL3_EWS << 24);
280 	}
281 
282 #ifdef DEBUG
283 	printf("%s: siop_ppr_neg: id now 0x%x, flags is now 0x%x\n",
284 	    sc->sc_dev.dv_xname, siop_target->id, siop_target->flags);
285 #endif
286 	tables->id = htole32(siop_target->id);
287 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3,
288 	    (siop_target->id >> 24) & 0xff);
289 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER,
290 	    (siop_target->id >> 8) & 0xff);
291 	/* Only cards with SCNTL4 can cause PPR negotiations, so ... */
292 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL4,
293 	    (siop_target->id & 0xff));
294 
295 	siop_target->status = TARST_OK;
296 	siop_print_info(sc, target);
297 
298 	return (SIOP_NEG_ACK);
299 }
300 
301 int
302 siop_wdtr_neg(siop_cmd)
303 	struct siop_cmd *siop_cmd;
304 {
305 	struct siop_softc *sc = siop_cmd->siop_sc;
306 	struct siop_target *siop_target = siop_cmd->siop_target;
307 	int target = siop_cmd->xs->sc_link->target;
308 	struct siop_xfer_common *tables = &siop_cmd->siop_xfer->tables;
309 
310 	/* revert to narrow async until told otherwise */
311 	sc->targets[target]->id    &= 0x07ff0000; /* Keep SCNTL3.CCF and id */
312 	sc->targets[target]->flags &= ~(TARF_ISWIDE | TARF_ISDT | TARF_ISQAS | TARF_ISIUS);
313 
314 	tables->id = htole32(sc->targets[target]->id);
315 
316 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3,
317 	    (sc->targets[target]->id >> 24) & 0xff);
318 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER,  0);
319 	if (sc->features & SF_CHIP_C10)
320 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL4, 0);
321 
322 	if (siop_target->status == TARST_WIDE_NEG) {
323 		/* we initiated wide negotiation */
324 		switch (tables->msg_in[3]) {
325 		case MSG_EXT_WDTR_BUS_8_BIT:
326 			siop_target->flags &= ~TARF_ISWIDE;
327 			sc->targets[target]->id &= ~(SCNTL3_EWS << 24);
328 			break;
329 		case MSG_EXT_WDTR_BUS_16_BIT:
330 			if (siop_target->flags & TARF_WIDE) {
331 				siop_target->flags |= TARF_ISWIDE;
332 				sc->targets[target]->id |= (SCNTL3_EWS << 24);
333 				break;
334 			}
335 		/* FALLTHROUGH */
336 		default:
337 			/*
338  			 * We got more than we can handle, which shouldn't
339 			 * happen. Reject, and stay async.
340 			 */
341 			siop_target->flags &= ~TARF_ISWIDE;
342 			siop_target->status = TARST_OK;
343 			printf("%s: rejecting invalid wide negotiation from "
344 			    "target %d (%d)\n", sc->sc_dev.dv_xname, target,
345 			    tables->msg_in[3]);
346 			siop_print_info(sc, target);
347 			tables->t_msgout.count= htole32(1);
348 			tables->msg_out[0] = MSG_MESSAGE_REJECT;
349 			return SIOP_NEG_MSGOUT;
350 		}
351 		tables->id = htole32(sc->targets[target]->id);
352 		bus_space_write_1(sc->sc_rt, sc->sc_rh,
353 		    SIOP_SCNTL3,
354 		    (sc->targets[target]->id >> 24) & 0xff);
355 		/* we now need to do sync */
356 		if (siop_target->flags & TARF_SYNC) {
357 			siop_target->status = TARST_SYNC_NEG;
358 			siop_sdtr_msg(siop_cmd, 0, sc->min_st_sync, sc->maxoff);
359 			return SIOP_NEG_MSGOUT;
360 		} else {
361 			siop_target->status = TARST_OK;
362 			siop_print_info(sc, target);
363 			return SIOP_NEG_ACK;
364 		}
365 	} else {
366 		/* target initiated wide negotiation */
367 		if (tables->msg_in[3] >= MSG_EXT_WDTR_BUS_16_BIT
368 		    && (siop_target->flags & TARF_WIDE)) {
369 			siop_target->flags |= TARF_ISWIDE;
370 			sc->targets[target]->id |= SCNTL3_EWS << 24;
371 		} else {
372 			siop_target->flags &= ~TARF_ISWIDE;
373 			sc->targets[target]->id &= ~(SCNTL3_EWS << 24);
374 		}
375 		tables->id = htole32(sc->targets[target]->id);
376 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3,
377 		    (sc->targets[target]->id >> 24) & 0xff);
378 		/*
379 		 * Don't schedule a sync neg, target should initiate it.
380 		 */
381 		if (siop_target->status != TARST_PROBING) {
382 			siop_target->status = TARST_OK;
383 			siop_print_info(sc, target);
384 		}
385 		siop_wdtr_msg(siop_cmd, 0, (siop_target->flags & TARF_ISWIDE) ?
386 		    MSG_EXT_WDTR_BUS_16_BIT : MSG_EXT_WDTR_BUS_8_BIT);
387 		return SIOP_NEG_MSGOUT;
388 	}
389 }
390 
391 int
392 siop_sdtr_neg(siop_cmd)
393 	struct siop_cmd *siop_cmd;
394 {
395 	struct siop_softc *sc = siop_cmd->siop_sc;
396 	struct siop_target *siop_target = siop_cmd->siop_target;
397 	int target = siop_cmd->xs->sc_link->target;
398 	int sync, offset, scf;
399 	int send_msgout = 0;
400 	struct siop_xfer_common *tables = &siop_cmd->siop_xfer->tables;
401 
402 	sync = tables->msg_in[3];
403 	offset = tables->msg_in[4];
404 
405 	/* revert to async until told otherwise */
406 	sc->targets[target]->id    &= 0x0fff0000; /* Keep SCNTL3.EWS, SCNTL3.CCF and id */
407 	sc->targets[target]->flags &= ~(TARF_ISDT | TARF_ISQAS | TARF_ISIUS);
408 
409 	if (siop_target->status == TARST_SYNC_NEG) {
410 		/* we initiated sync negotiation */
411 #ifdef DEBUG
412 		printf("%s: sdtr for target %d: sync %d offset %d\n",
413 		    sc->sc_dev.dv_xname, target, sync, offset);
414 #endif
415 		scf = siop_period_factor_to_scf(sc, sync, sc->targets[target]->flags);
416 		if (offset > sc->maxoff || scf == 0)
417 			goto reject;
418 		sc->targets[target]->id |= scf << (24 + SCNTL3_SCF_SHIFT);
419 		if (((sc->features & SF_CHIP_C10) == 0) && (sync < 25))
420 			sc->targets[target]->id |= SCNTL3_ULTRA << 24;
421 		sc->targets[target]->id |= (offset & 0xff) << 8;
422 		goto end;
423 		/*
424 		 * We didn't find it in our table, so stay async and send reject
425 		 * msg.
426 		 */
427 reject:
428 		send_msgout = 1;
429 		tables->t_msgout.count= htole32(1);
430 		tables->msg_out[0] = MSG_MESSAGE_REJECT;
431 	} else { /* target initiated sync neg */
432 #ifdef DEBUG
433 		printf("%s: target initiated sdtr for target %d: sync %d offset %d\n",
434 		    sc->sc_dev.dv_xname, target, sync, offset);
435 		printf("sdtr (target): sync %d offset %d\n", sync, offset);
436 #endif
437 		if (sync < sc->min_st_sync)
438 			sync = sc->min_st_sync;
439 		scf = siop_period_factor_to_scf(sc, sync, sc->targets[target]->flags);
440 		if ((sc->targets[target]->flags & TARF_SYNC) == 0
441 		    || offset == 0
442 		    || scf == 0) {
443 			goto async;
444 		}
445 		if ((offset > 31) && ((sc->targets[target]->flags & TARF_ISDT) == 0))
446 			offset = 31;
447 		if (offset > sc->maxoff)
448 			offset = sc->maxoff;
449 
450 		sc->targets[target]->id |= scf << (24 + SCNTL3_SCF_SHIFT);
451 		if (((sc->features & SF_CHIP_C10) == 0) && (sync < 25))
452 			sc->targets[target]->id |= SCNTL3_ULTRA << 24;
453 		sc->targets[target]->id |= (offset & 0xff) << 8;
454 		siop_sdtr_msg(siop_cmd, 0, sync, offset);
455 		send_msgout = 1;
456 		goto end;
457 async:
458 		siop_sdtr_msg(siop_cmd, 0, 0, 0);
459 		send_msgout = 1;
460 	}
461 end:
462 #ifdef DEBUG
463 	printf("id now 0x%x\n", sc->targets[target]->id);
464 #endif
465 	tables->id = htole32(sc->targets[target]->id);
466 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3,
467 	    (sc->targets[target]->id >> 24) & 0xff);
468 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER,
469 	    (sc->targets[target]->id >> 8) & 0xff);
470 
471 	if (siop_target->status != TARST_PROBING) {
472 		siop_target->status = TARST_OK;
473 		siop_print_info(sc, target);
474 	}
475 
476 	if (send_msgout) {
477 		return SIOP_NEG_MSGOUT;
478 	} else {
479 		return SIOP_NEG_ACK;
480 	}
481 }
482 
483 void
484 siop_ppr_msg(siop_cmd, offset, ssync, soff)
485 	struct siop_cmd *siop_cmd;
486 	int offset, ssync, soff;
487 {
488 	struct siop_softc *sc = siop_cmd->siop_sc;
489 	u_int8_t protocol;
490 
491 	siop_cmd->siop_tables.msg_out[offset + 0] = MSG_EXTENDED;
492 	siop_cmd->siop_tables.msg_out[offset + 1] = MSG_EXT_PPR_LEN;
493 	siop_cmd->siop_tables.msg_out[offset + 2] = MSG_EXT_PPR;
494 	siop_cmd->siop_tables.msg_out[offset + 3] = ssync;
495 	siop_cmd->siop_tables.msg_out[offset + 4] = 0; /* RESERVED */
496 	siop_cmd->siop_tables.msg_out[offset + 5] = soff;
497 	siop_cmd->siop_tables.msg_out[offset + 6] = MSG_EXT_WDTR_BUS_16_BIT;
498 
499 	protocol = 0;
500 	if (sc->min_dt_sync != 0)
501 		protocol |= MSG_EXT_PPR_PROT_DT;
502 
503 	/* XXX - need tests for chip's capability to do QAS & IUS
504 	 *
505 	 * if (test for QAS support)
506 	 *         protocol |= MSG_EXT_PPR_PROT_QAS;
507 	 * if (test for IUS support)
508 	 *         protocol |= MSG_EXT_PPR_PROT_IUS;
509 	 */
510 
511 	siop_cmd->siop_tables.msg_out[offset + 7] = protocol;
512 
513 	siop_cmd->siop_tables.t_msgout.count =
514 	    htole32(offset + MSG_EXT_PPR_LEN + 2);
515 }
516 
517 void
518 siop_sdtr_msg(siop_cmd, offset, ssync, soff)
519 	struct siop_cmd *siop_cmd;
520 	int offset;
521 	int ssync, soff;
522 {
523 	siop_cmd->siop_tables.msg_out[offset + 0] = MSG_EXTENDED;
524 	siop_cmd->siop_tables.msg_out[offset + 1] = MSG_EXT_SDTR_LEN;
525 	siop_cmd->siop_tables.msg_out[offset + 2] = MSG_EXT_SDTR;
526 	siop_cmd->siop_tables.msg_out[offset + 3] = ssync;
527 
528 	if ((soff > 31) && ((siop_cmd->siop_target->flags & TARF_ISDT) == 0))
529 		soff = 31;
530 
531 	siop_cmd->siop_tables.msg_out[offset + 4] = soff;
532 	siop_cmd->siop_tables.t_msgout.count =
533 	    htole32(offset + MSG_EXT_SDTR_LEN + 2);
534 }
535 
536 void
537 siop_wdtr_msg(siop_cmd, offset, wide)
538 	struct siop_cmd *siop_cmd;
539 	int offset;
540 {
541 	siop_cmd->siop_tables.msg_out[offset + 0] = MSG_EXTENDED;
542 	siop_cmd->siop_tables.msg_out[offset + 1] = MSG_EXT_WDTR_LEN;
543 	siop_cmd->siop_tables.msg_out[offset + 2] = MSG_EXT_WDTR;
544 	siop_cmd->siop_tables.msg_out[offset + 3] = wide;
545 	siop_cmd->siop_tables.t_msgout.count =
546 	    htole32(offset + MSG_EXT_WDTR_LEN + 2);
547 }
548 
549 void
550 siop_minphys(bp)
551 	struct buf *bp;
552 {
553 	minphys(bp);
554 }
555 
556 void
557 siop_sdp(siop_cmd)
558 	struct siop_cmd *siop_cmd;
559 {
560 	/* save data pointer. Handle async only for now */
561 	int offset, dbc, sstat;
562 	struct siop_softc *sc = siop_cmd->siop_sc;
563 	struct scr_table *table; /* table to patch */
564 
565 	if ((siop_cmd->xs->flags & (SCSI_DATA_OUT | SCSI_DATA_IN))
566 	    == 0)
567 	    return; /* no data pointers to save */
568 	offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA + 1);
569 	if (offset >= SIOP_NSG) {
570 		printf("%s: bad offset in siop_sdp (%d)\n",
571 		    sc->sc_dev.dv_xname, offset);
572 		return;
573 	}
574 	table = &siop_cmd->siop_xfer->tables.data[offset];
575 #ifdef DEBUG_DR
576 	printf("sdp: offset %d count=%d addr=0x%x ", offset,
577 	    table->count, table->addr);
578 #endif
579 	dbc = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DBC) & 0x00ffffff;
580 	if (siop_cmd->xs->flags & SCSI_DATA_OUT) {
581 		/* need to account for stale data in FIFO */
582 		if (sc->features & SF_CHIP_C10)
583 			dbc += bus_space_read_2(sc->sc_rt, sc->sc_rh, SIOP_DFBC);
584 		else {
585 			int dfifo = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DFIFO);
586 			if (sc->features & SF_CHIP_FIFO) {
587 				dfifo |= (bus_space_read_1(sc->sc_rt, sc->sc_rh,
588 					      SIOP_CTEST5) & CTEST5_BOMASK) << 8;
589 				dbc += (dfifo - (dbc & 0x3ff)) & 0x3ff;
590 			} else {
591 				dbc += (dfifo - (dbc & 0x7f)) & 0x7f;
592 			}
593 		}
594 		sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT0);
595 		if (sstat & SSTAT0_OLF)
596 			dbc++;
597 		if ((sc->features & SF_CHIP_C10) == 0)
598 			if (sstat & SSTAT0_ORF)
599 				dbc++;
600 		if (siop_cmd->siop_target->flags & TARF_ISWIDE) {
601 			sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh,
602 			    SIOP_SSTAT2);
603 			if (sstat & SSTAT2_OLF1)
604 				dbc++;
605 			if ((sc->features & SF_CHIP_C10) == 0)
606 				if (sstat & SSTAT2_ORF1)
607 					dbc++;
608 		}
609 		/* clear the FIFO */
610 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
611 		    bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) |
612 		    CTEST3_CLF);
613 	}
614 	table->addr =
615 	    htole32(letoh32(table->addr) + letoh32(table->count) - dbc);
616 	table->count = htole32(dbc);
617 #ifdef DEBUG_DR
618 	printf("now count=%d addr=0x%x\n", table->count, table->addr);
619 #endif
620 }
621 
622 void
623 siop_clearfifo(sc)
624 	struct siop_softc *sc;
625 {
626 	int timeout = 0;
627 	int ctest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3);
628 
629 #ifdef SIOP_DEBUG_INTR
630 	printf("DMA fifo not empty!\n");
631 #endif
632 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
633 	    ctest3 | CTEST3_CLF);
634 	while ((bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) &
635 	    CTEST3_CLF) != 0) {
636 		delay(1);
637 		if (++timeout > 1000) {
638 			printf("clear fifo failed\n");
639 			bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
640 			    bus_space_read_1(sc->sc_rt, sc->sc_rh,
641 			    SIOP_CTEST3) & ~CTEST3_CLF);
642 			return;
643 		}
644 	}
645 }
646 
647 int
648 siop_modechange(sc)
649 	struct siop_softc *sc;
650 {
651 	int retry;
652 	int sist0, sist1, stest2, stest4;
653 	for (retry = 0; retry < 5; retry++) {
654 		/*
655 		 * Datasheet says to wait 100ms and re-read SIST1,
656 		 * to check that DIFFSENSE is stable.
657 		 * We may delay() 5 times for 100ms at interrupt time;
658 		 * hopefully this will not happen often.
659 		 */
660 		delay(100000);
661 		sist0 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST0);
662 		sist1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST1);
663 		if (sist1 & SIEN1_SBMC)
664 			continue; /* we got an irq again */
665 		stest4 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST4) &
666 		    STEST4_MODE_MASK;
667 		stest2 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2);
668 		switch(stest4) {
669 		case STEST4_MODE_DIF:
670 			if (sc->features & SF_CHIP_C10) {
671 				printf("%s: invalid SCSI mode 0x%x\n",
672 				    sc->sc_dev.dv_xname, stest4);
673 				return 0;
674 			} else {
675 				printf("%s: switching to differential mode\n",
676 				    sc->sc_dev.dv_xname);
677 				bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2,
678 				    stest2 | STEST2_DIF);
679 			}
680 			break;
681 		case STEST4_MODE_SE:
682 			printf("%s: switching to single-ended mode\n",
683 			    sc->sc_dev.dv_xname);
684 			bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2,
685 			    stest2 & ~STEST2_DIF);
686 			break;
687 		case STEST4_MODE_LVD:
688 			printf("%s: switching to LVD mode\n",
689 			    sc->sc_dev.dv_xname);
690 			bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2,
691 			    stest2 & ~STEST2_DIF);
692 			break;
693 		default:
694 			printf("%s: invalid SCSI mode 0x%x\n",
695 			    sc->sc_dev.dv_xname, stest4);
696 			return 0;
697 		}
698 		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST0,
699 		    stest4 >> 2);
700 		return 1;
701 	}
702 	printf("%s: timeout waiting for DIFFSENSE to stabilise\n",
703 	    sc->sc_dev.dv_xname);
704 	return 0;
705 }
706 
707 void
708 siop_resetbus(sc)
709 	struct siop_softc *sc;
710 {
711 	int scntl1;
712 	scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1);
713 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1,
714 	    scntl1 | SCNTL1_RST);
715 	/* minimum 25 us, more time won't hurt */
716 	delay(100);
717 	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);
718 }
719 
720 /*
721  * siop_print_info: print the current negotiated wide/sync xfer values for
722  *                  a particular target. This function is called whenever
723  *		    a wide/sync negotiation completes, i.e. whenever
724  *		    target->status is set to TARST_OK.
725  */
726 void
727 siop_print_info(sc, target)
728         struct siop_softc *sc;
729         int target;
730 {
731 	struct siop_target *siop_target;
732 	u_int8_t scf, offset;
733 	int scf_index, factors, i;
734 
735 	siop_target = sc->targets[target];
736 
737 	printf("%s: target %d now using %s%s%s%s%d bit ",
738             sc->sc_dev.dv_xname, target,
739 	    (siop_target->flags & TARF_TAG) ? "tagged " : "",
740 	    (siop_target->flags & TARF_ISDT) ? "DT " : "",
741 	    (siop_target->flags & TARF_ISQAS) ? "QAS " : "",
742 	    (siop_target->flags & TARF_ISIUS) ? "IUS " : "",
743 	    (siop_target->flags & TARF_ISWIDE) ? 16 : 8);
744 
745 	offset = ((siop_target->id >> 8) & 0xff) >> SXFER_MO_SHIFT;
746 
747 	if (offset == 0)
748 		printf("async ");
749 	else {
750 		factors = sizeof(period_factor) / sizeof(period_factor[0]);
751 
752 		scf = ((siop_target->id >> 24) & SCNTL3_SCF_MASK) >> SCNTL3_SCF_SHIFT;
753 		scf_index = sc->scf_index;
754 
755 		for (i = 0; i < factors; i++)
756 			if (siop_target->flags & TARF_ISDT) {
757 				if (period_factor[i].scf[scf_index].dt_scf == scf)
758 					break;
759 			}
760 			else if	(period_factor[i].scf[scf_index].st_scf == scf)
761 				break;
762 
763 		if (i >= factors)
764 			printf("?? ");
765 		else
766 			printf("%s ", period_factor[i].rate);
767 
768 		printf("MHz %d REQ/ACK offset ", offset);
769 	}
770 
771 	printf("xfers\n");
772 }
773 
774 int
775 siop_period_factor_to_scf(sc, pf, flags)
776 	struct siop_softc *sc;
777 	int pf, flags;
778 {
779 	const int scf_index = sc->scf_index;
780 	int i;
781 
782 	const int factors = sizeof(period_factor) / sizeof(period_factor[0]);
783 
784 	for (i = 0; i < factors; i++)
785 		if (period_factor[i].factor == pf) {
786 			if (flags & TARF_ISDT)
787 				return (period_factor[i].scf[scf_index].dt_scf);
788 			else
789 				return (period_factor[i].scf[scf_index].st_scf);
790 		}
791 
792 	return (0);
793 }
794