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