siop_common.c revision 1.4 1 /* $NetBSD: siop_common.c,v 1.4 2000/06/26 14:21:10 mrg Exp $ */
2
3 /*
4 * Copyright (c) 2000 Manuel Bouyer.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Manuel Bouyer
17 * 4. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 */
32
33 /* SYM53c7/8xx PCI-SCSI I/O Processors driver */
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/device.h>
38 #include <sys/malloc.h>
39 #include <sys/buf.h>
40 #include <sys/kernel.h>
41 #include <sys/scsiio.h>
42
43 #include <machine/endian.h>
44 #include <machine/bus.h>
45
46 #include <vm/vm.h>
47
48 #include <dev/scsipi/scsi_all.h>
49 #include <dev/scsipi/scsi_message.h>
50 #include <dev/scsipi/scsipi_all.h>
51
52 #include <dev/scsipi/scsiconf.h>
53
54 #include <dev/ic/siopreg.h>
55 #include <dev/ic/siopvar.h>
56 #include <dev/ic/siopvar_common.h>
57
58 #undef DEBUG
59 #undef DEBUG_DR
60
61 void
62 siop_common_reset(sc)
63 struct siop_softc *sc;
64 {
65 u_int32_t stest3;
66
67 /* reset the chip */
68 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SRST);
69 delay(1000);
70 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, 0);
71
72 /* init registers */
73 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL0,
74 SCNTL0_ARB_MASK | SCNTL0_EPC | SCNTL0_AAP);
75 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, 0);
76 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, sc->clock_div);
77 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCXFER, 0);
78 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DIEN, 0xff);
79 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN0,
80 0xff & ~(SIEN0_CMP | SIEN0_SEL | SIEN0_RSL));
81 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN1,
82 0xff & ~(SIEN1_HTH | SIEN1_GEN));
83 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, 0);
84 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, STEST3_TE);
85 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STIME0,
86 (0xb << STIME0_SEL_SHIFT));
87 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCID,
88 sc->sc_link.scsipi_scsi.adapter_target | SCID_RRE);
89 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_RESPID0,
90 1 << sc->sc_link.scsipi_scsi.adapter_target);
91 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DCNTL,
92 (sc->features & SF_CHIP_PF) ? DCNTL_COM | DCNTL_PFEN : DCNTL_COM);
93
94 /* enable clock doubler or quadruler if appropriate */
95 if (sc->features & (SF_CHIP_DBLR | SF_CHIP_QUAD)) {
96 stest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3);
97 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1,
98 STEST1_DBLEN);
99 if (sc->features & SF_CHIP_QUAD) {
100 /* wait for PPL to lock */
101 while ((bus_space_read_1(sc->sc_rt, sc->sc_rh,
102 SIOP_STEST4) & STEST4_LOCK) == 0)
103 delay(10);
104 } else {
105 /* data sheet says 20us - more won't hurt */
106 delay(100);
107 }
108 /* halt scsi clock, select doubler/quad, restart clock */
109 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3,
110 stest3 | STEST3_HSC);
111 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1,
112 STEST1_DBLEN | STEST1_DBLSEL);
113 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, stest3);
114 } else {
115 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1, 0);
116 }
117 if (sc->features & SF_CHIP_FIFO)
118 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST5,
119 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST5) |
120 CTEST5_DFS);
121
122 sc->sc_reset(sc);
123 }
124
125 int
126 siop_wdtr_neg(siop_cmd)
127 struct siop_cmd *siop_cmd;
128 {
129 struct siop_softc *sc = siop_cmd->siop_target->siop_sc;
130 struct siop_target *siop_target = siop_cmd->siop_target;
131 int target = siop_cmd->xs->sc_link->scsipi_scsi.target;
132
133 if (siop_target->status == TARST_WIDE_NEG) {
134 /* we initiated wide negotiation */
135 switch (siop_cmd->siop_table->msg_in[3]) {
136 case MSG_EXT_WDTR_BUS_8_BIT:
137 printf("%s: target %d using 8bit transfers\n",
138 sc->sc_dev.dv_xname, target);
139 siop_target->flags &= ~SF_BUS_WIDE;
140 sc->targets[target]->id &= ~(SCNTL3_EWS << 24);
141 break;
142 case MSG_EXT_WDTR_BUS_16_BIT:
143 if (sc->features & SF_BUS_WIDE) {
144 printf("%s: target %d using 16bit transfers\n",
145 sc->sc_dev.dv_xname, target);
146 siop_target->flags |= TARF_WIDE;
147 sc->targets[target]->id |= (SCNTL3_EWS << 24);
148 break;
149 }
150 /* FALLTHROUH */
151 default:
152 /*
153 * hum, we got more than what we can handle, shoudn't
154 * happen. Reject, and stay async
155 */
156 siop_target->flags &= ~TARF_WIDE;
157 siop_target->status = TARST_OK;
158 printf("%s: rejecting invalid wide negotiation from "
159 "target %d (%d)\n", sc->sc_dev.dv_xname, target,
160 siop_cmd->siop_table->msg_in[3]);
161 siop_cmd->siop_table->t_msgout.count= htole32(1);
162 siop_cmd->siop_table->t_msgout.addr =
163 htole32(siop_cmd->dsa);
164 siop_cmd->siop_table->msg_out[0] = MSG_MESSAGE_REJECT;
165 return SIOP_NEG_MSGOUT;
166 }
167 siop_cmd->siop_table->id =
168 htole32(sc->targets[target]->id);
169 bus_space_write_1(sc->sc_rt, sc->sc_rh,
170 SIOP_SCNTL3,
171 (sc->targets[target]->id >> 24) & 0xff);
172 /* we now need to do sync */
173 siop_target->status = TARST_SYNC_NEG;
174 siop_cmd->siop_table->msg_out[0] = MSG_EXTENDED;
175 siop_cmd->siop_table->msg_out[1] = MSG_EXT_SDTR_LEN;
176 siop_cmd->siop_table->msg_out[2] = MSG_EXT_SDTR;
177 siop_cmd->siop_table->msg_out[3] = sc->minsync;
178 siop_cmd->siop_table->msg_out[4] = sc->maxoff;
179 siop_cmd->siop_table->t_msgout.count =
180 htole32(MSG_EXT_SDTR_LEN + 2);
181 siop_cmd->siop_table->t_msgout.addr = htole32(siop_cmd->dsa);
182 return SIOP_NEG_MSGOUT;
183 } else {
184 /* target initiated wide negotiation */
185 if (siop_cmd->siop_table->msg_in[3] >= MSG_EXT_WDTR_BUS_16_BIT
186 && (sc->features & SF_BUS_WIDE)) {
187 printf("%s: target %d using 16bit transfers\n",
188 sc->sc_dev.dv_xname, target);
189 siop_target->flags |= TARF_WIDE;
190 sc->targets[target]->id |= SCNTL3_EWS << 24;
191 siop_cmd->siop_table->msg_out[3] =
192 MSG_EXT_WDTR_BUS_16_BIT;
193 } else {
194 printf("%s: target %d using 8bit transfers\n",
195 sc->sc_dev.dv_xname, target);
196 siop_target->flags &= ~SF_BUS_WIDE;
197 sc->targets[target]->id &= ~(SCNTL3_EWS << 24);
198 siop_cmd->siop_table->msg_out[3] =
199 MSG_EXT_WDTR_BUS_8_BIT;
200 }
201 siop_cmd->siop_table->id =
202 htole32(sc->targets[target]->id);
203 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3,
204 (sc->targets[target]->id >> 24) & 0xff);
205 /*
206 * we did reset wide parameters, so fall back to async,
207 * but don't shedule a sync neg, target should initiate it
208 */
209 siop_target->status = TARST_OK;
210 siop_cmd->siop_table->msg_out[0] = MSG_EXTENDED;
211 siop_cmd->siop_table->msg_out[1] = MSG_EXT_WDTR_LEN;
212 siop_cmd->siop_table->msg_out[2] = MSG_EXT_WDTR;
213 siop_cmd->siop_table->t_msgout.count=
214 htole32(MSG_EXT_WDTR_LEN + 2);
215 siop_cmd->siop_table->t_msgout.addr = htole32(siop_cmd->dsa);
216 return SIOP_NEG_MSGOUT;
217 }
218 }
219
220 int
221 siop_sdtr_neg(siop_cmd)
222 struct siop_cmd *siop_cmd;
223 {
224 struct siop_softc *sc = siop_cmd->siop_target->siop_sc;
225 struct siop_target *siop_target = siop_cmd->siop_target;
226 int target = siop_cmd->xs->sc_link->scsipi_scsi.target;
227 int sync, offset, i;
228 int send_msgout = 0;
229
230 sync = siop_cmd->siop_table->msg_in[3];
231 offset = siop_cmd->siop_table->msg_in[4];
232
233 if (siop_target->status == TARST_SYNC_NEG) {
234 /* we initiated sync negotiation */
235 siop_target->status = TARST_OK;
236 #ifdef DEBUG
237 printf("sdtr: sync %d offset %d\n", sync, offset);
238 #endif
239 if (offset > sc->maxoff || sync < sc->minsync ||
240 sync > sc->maxsync)
241 goto reject;
242 for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]);
243 i++) {
244 if (sc->clock_period != scf_period[i].clock)
245 continue;
246 if (scf_period[i].period == sync) {
247 /* ok, found it. we now are sync. */
248 printf("%s: target %d now synchronous at "
249 "%sMhz, offset %d\n", sc->sc_dev.dv_xname,
250 target, scf_period[i].rate, offset);
251 sc->targets[target]->id &=
252 ~(SCNTL3_SCF_MASK << 24);
253 sc->targets[target]->id |= scf_period[i].scf
254 << (24 + SCNTL3_SCF_SHIFT);
255 if (sync < 25) /* Ultra */
256 sc->targets[target]->id |=
257 SCNTL3_ULTRA << 24;
258 else
259 sc->targets[target]->id &=
260 ~(SCNTL3_ULTRA << 24);
261 sc->targets[target]->id &=
262 ~(SCXFER_MO_MASK << 8);
263 sc->targets[target]->id |=
264 (offset & SCXFER_MO_MASK) << 8;
265 goto end;
266 }
267 }
268 /*
269 * we didn't find it in our table, do async and send reject
270 * msg
271 */
272 reject:
273 send_msgout = 1;
274 siop_cmd->siop_table->t_msgout.count= htole32(1);
275 siop_cmd->siop_table->msg_out[0] = MSG_MESSAGE_REJECT;
276 printf("%s: target %d asynchronous\n", sc->sc_dev.dv_xname,
277 target);
278 sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24);
279 sc->targets[target]->id &= ~(SCNTL3_ULTRA << 24);
280 sc->targets[target]->id &= ~(SCXFER_MO_MASK << 8);
281 } else { /* target initiated sync neg */
282 #ifdef DEBUG
283 printf("sdtr (target): sync %d offset %d\n", sync, offset);
284 #endif
285 if (offset == 0 || sync > sc->maxsync) { /* async */
286 goto async;
287 }
288 if (offset > sc->maxoff)
289 offset = sc->maxoff;
290 if (sync < sc->minsync)
291 sync = sc->minsync;
292 /* look for sync period */
293 for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]);
294 i++) {
295 if (sc->clock_period != scf_period[i].clock)
296 continue;
297 if (scf_period[i].period == sync) {
298 /* ok, found it. we now are sync. */
299 printf("%s: target %d now synchronous at "
300 "%sMhz, offset %d\n", sc->sc_dev.dv_xname,
301 target, scf_period[i].rate, offset);
302 sc->targets[target]->id &=
303 ~(SCNTL3_SCF_MASK << 24);
304 sc->targets[target]->id |= scf_period[i].scf
305 << (24 + SCNTL3_SCF_SHIFT);
306 if (sync < 25) /* Ultra */
307 sc->targets[target]->id |=
308 SCNTL3_ULTRA << 24;
309 else
310 sc->targets[target]->id &=
311 ~(SCNTL3_ULTRA << 24);
312 sc->targets[target]->id &=
313 ~(SCXFER_MO_MASK << 8);
314 sc->targets[target]->id |=
315 (offset & SCXFER_MO_MASK) << 8;
316 siop_cmd->siop_table->msg_out[0] = MSG_EXTENDED;
317 siop_cmd->siop_table->msg_out[1] =
318 MSG_EXT_SDTR_LEN;
319 siop_cmd->siop_table->msg_out[2] = MSG_EXT_SDTR;
320 siop_cmd->siop_table->msg_out[3] = sync;
321 siop_cmd->siop_table->msg_out[4] = offset;
322 siop_cmd->siop_table->t_msgout.count=
323 htole32(MSG_EXT_SDTR_LEN + 2);
324 send_msgout = 1;
325 goto end;
326 }
327 }
328 async:
329 printf("%s: target %d asynchronous\n",
330 sc->sc_dev.dv_xname, target);
331 sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24);
332 sc->targets[target]->id &= ~(SCNTL3_ULTRA << 24);
333 sc->targets[target]->id &= ~(SCXFER_MO_MASK << 8);
334 siop_cmd->siop_table->msg_out[0] = MSG_EXTENDED;
335 siop_cmd->siop_table->msg_out[1] = MSG_EXT_SDTR_LEN;
336 siop_cmd->siop_table->msg_out[2] = MSG_EXT_SDTR;
337 siop_cmd->siop_table->msg_out[3] = 0;
338 siop_cmd->siop_table->msg_out[4] = 0;
339 siop_cmd->siop_table->t_msgout.count=
340 htole32(MSG_EXT_SDTR_LEN + 2);
341 send_msgout = 1;
342 }
343 end:
344 #ifdef DEBUG
345 printf("id now 0x%x\n", sc->targets[target]->id);
346 #endif
347 siop_cmd->siop_table->id = htole32(sc->targets[target]->id);
348 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3,
349 (sc->targets[target]->id >> 24) & 0xff);
350 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCXFER,
351 (sc->targets[target]->id >> 8) & 0xff);
352 if (send_msgout) {
353 siop_cmd->siop_table->t_msgout.addr = htole32(siop_cmd->dsa);
354 return SIOP_NEG_MSGOUT;
355 } else {
356 return SIOP_NEG_ACK;
357 }
358 }
359
360 void
361 siop_minphys(bp)
362 struct buf *bp;
363 {
364 minphys(bp);
365 }
366
367 int
368 siop_ioctl(link, cmd, arg, flag, p)
369 struct scsipi_link *link;
370 u_long cmd;
371 caddr_t arg;
372 int flag;
373 struct proc *p;
374 {
375 struct siop_softc *sc = link->adapter_softc;
376 u_int8_t scntl1;
377 int s;
378
379 switch (cmd) {
380 case SCBUSIORESET:
381 s = splbio();
382 scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1);
383 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1,
384 scntl1 | SCNTL1_RST);
385 /* minimum 25 us, more time won't hurt */
386 delay(100);
387 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);
388 splx(s);
389 return (0);
390 default:
391 return (ENOTTY);
392 }
393 }
394
395 void
396 siop_sdp(siop_cmd)
397 struct siop_cmd *siop_cmd;
398 {
399 /* save data pointer. Handle async only for now */
400 int offset, dbc, sstat;
401 struct siop_softc *sc = siop_cmd->siop_target->siop_sc;
402 scr_table_t *table; /* table to patch */
403
404 if ((siop_cmd->xs->xs_control & (XS_CTL_DATA_OUT | XS_CTL_DATA_IN))
405 == 0)
406 return; /* no data pointers to save */
407 offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA + 1);
408 if (offset >= SIOP_NSG) {
409 printf("%s: bad offset in siop_sdp (%d)\n",
410 sc->sc_dev.dv_xname, offset);
411 return;
412 }
413 table = &siop_cmd->siop_table->data[offset];
414 #ifdef DEBUG_DR
415 printf("sdp: offset %d count=%d addr=0x%x ", offset,
416 table->count, table->addr);
417 #endif
418 dbc = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DBC) & 0x00ffffff;
419 if (siop_cmd->xs->xs_control & XS_CTL_DATA_OUT) {
420 /* need to account stale data in FIFO */
421 int dfifo = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DFIFO);
422 if (sc->features & SF_CHIP_FIFO) {
423 dfifo |= (bus_space_read_1(sc->sc_rt, sc->sc_rh,
424 SIOP_CTEST5) & CTEST5_BOMASK) << 8;
425 dbc += (dfifo - (dbc & 0x3ff)) & 0x3ff;
426 } else {
427 dbc += (dfifo - (dbc & 0x7f)) & 0x7f;
428 }
429 sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT0);
430 if (sstat & SSTAT0_OLF)
431 dbc++;
432 if (sstat & SSTAT0_ORF)
433 dbc++;
434 if (siop_cmd->siop_target->flags & TARF_WIDE) {
435 sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh,
436 SIOP_SSTAT2);
437 if (sstat & SSTAT2_OLF1)
438 dbc++;
439 if (sstat & SSTAT2_ORF1)
440 dbc++;
441 }
442 /* clear the FIFO */
443 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
444 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) |
445 CTEST3_CLF);
446 }
447 table->addr =
448 htole32(le32toh(table->addr) + le32toh(table->count) - dbc);
449 table->count = htole32(dbc);
450 #ifdef DEBUG_DR
451 printf("now count=%d addr=0x%x\n", table->count, table->addr);
452 #endif
453 }
454
455 void
456 siop_clearfifo(sc)
457 struct siop_softc *sc;
458 {
459 int timeout = 0;
460 int ctest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3);
461
462 #ifdef DEBUG_INTR
463 printf("DMA fifo not empty !\n");
464 #endif
465 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
466 ctest3 | CTEST3_CLF);
467 while ((bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) &
468 CTEST3_CLF) != 0) {
469 delay(1);
470 if (++timeout > 1000) {
471 printf("clear fifo failed\n");
472 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
473 bus_space_read_1(sc->sc_rt, sc->sc_rh,
474 SIOP_CTEST3) & ~CTEST3_CLF);
475 return;
476 }
477 }
478 }
479
480 int
481 siop_modechange(sc)
482 struct siop_softc *sc;
483 {
484 int retry;
485 int sist0, sist1, stest2, stest4;
486 for (retry = 0; retry < 5; retry++) {
487 /*
488 * datasheet says to wait 100ms and re-read SIST1,
489 * to check that DIFFSENSE is srable.
490 * We may delay() 5 times for 100ms at interrupt time;
491 * hopefully this will not happen often.
492 */
493 delay(100000);
494 sist0 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST0);
495 sist1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST1);
496 if (sist1 & SIEN1_SBMC)
497 continue; /* we got an irq again */
498 stest4 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST4) &
499 STEST4_MODE_MASK;
500 stest2 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2);
501 switch(stest4) {
502 case STEST4_MODE_DIF:
503 printf("%s: switching to differential mode\n",
504 sc->sc_dev.dv_xname);
505 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2,
506 stest2 | STEST2_DIF);
507 break;
508 case STEST4_MODE_SE:
509 printf("%s: switching to single-ended mode\n",
510 sc->sc_dev.dv_xname);
511 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2,
512 stest2 & ~STEST2_DIF);
513 break;
514 case STEST4_MODE_LVD:
515 printf("%s: switching to LVD mode\n",
516 sc->sc_dev.dv_xname);
517 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2,
518 stest2 & ~STEST2_DIF);
519 break;
520 default:
521 printf("%s: invalid SCSI mode 0x%x\n",
522 sc->sc_dev.dv_xname, stest4);
523 return 0;
524 }
525 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST0,
526 stest4 >> 2);
527 return 1;
528 }
529 printf("%s: timeout waiting for DIFFSENSE to stabilise\n",
530 sc->sc_dev.dv_xname);
531 return 0;
532 }
533