xref: /openbsd/sys/dev/ic/aic79xx_openbsd.c (revision cca36db2)
1 /*	$OpenBSD: aic79xx_openbsd.c,v 1.38 2012/02/24 06:19:00 guenther Exp $	*/
2 
3 /*
4  * Copyright (c) 2004 Milos Urbanek, Kenneth R. Westerback & Marco Peereboom
5  * All rights reserved.
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  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  */
29 
30 /*
31  * Bus independent OpenBSD shim for the aic79xx based Adaptec SCSI controllers
32  *
33  * Copyright (c) 1994-2002 Justin T. Gibbs.
34  * Copyright (c) 2001-2002 Adaptec Inc.
35  * All rights reserved.
36  *
37  * Redistribution and use in source and binary forms, with or without
38  * modification, are permitted provided that the following conditions
39  * are met:
40  * 1. Redistributions of source code must retain the above copyright
41  *    notice, this list of conditions, and the following disclaimer,
42  *    without modification.
43  * 2. The name of the author may not be used to endorse or promote products
44  *    derived from this software without specific prior written permission.
45  *
46  * Alternatively, this software may be distributed under the terms of the
47  * GNU Public License ("GPL").
48  *
49  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
50  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
53  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59  * SUCH DAMAGE.
60  *
61  */
62 
63 #include <sys/cdefs.h>
64 /*
65 __FBSDID("$FreeBSD: src/sys/dev/aic7xxx/aic79xx_osm.c,v 1.16 2003/12/17 00:02:09 gibbs Exp $");
66 */
67 
68 #include <dev/ic/aic79xx_openbsd.h>
69 #include <dev/ic/aic79xx_inline.h>
70 #include <dev/ic/aic79xx.h>
71 
72 #ifndef AHD_TMODE_ENABLE
73 #define AHD_TMODE_ENABLE 0
74 #endif
75 
76 /* XXX milos add ahd_ioctl */
77 void	ahd_action(struct scsi_xfer *);
78 void	ahd_execute_scb(void *, bus_dma_segment_t *, int);
79 int	ahd_poll(struct ahd_softc *, int);
80 void	ahd_setup_data(struct ahd_softc *, struct scsi_xfer *,
81 		    struct scb *);
82 
83 void	ahd_adapter_req_set_xfer_mode(struct ahd_softc *, struct scb *);
84 void    ahd_minphys(struct buf *, struct scsi_link *);
85 
86 struct cfdriver ahd_cd = {
87 	NULL, "ahd", DV_DULL
88 };
89 
90 static struct scsi_adapter ahd_switch =
91 {
92 	ahd_action,
93 	ahd_minphys,
94 	0,
95 	0,
96 };
97 
98 /*
99  * Attach all the sub-devices we can find
100  */
101 int
102 ahd_attach(struct ahd_softc *ahd)
103 {
104 	struct scsibus_attach_args saa;
105 	char   ahd_info[256];
106 	int	s;
107 
108 	ahd_controller_info(ahd, ahd_info, sizeof ahd_info);
109 	printf("%s\n", ahd_info);
110 	ahd_lock(ahd, &s);
111 
112 	/*
113 	 * fill in the prototype scsi_links.
114 	 */
115 	ahd->sc_channel.adapter_target = ahd->our_id;
116 	if (ahd->features & AHD_WIDE)
117 		ahd->sc_channel.adapter_buswidth = 16;
118 	ahd->sc_channel.adapter_softc = ahd;
119 	ahd->sc_channel.adapter = &ahd_switch;
120 	ahd->sc_channel.openings = 16;
121 
122 	if (bootverbose) {
123 		ahd_controller_info(ahd, ahd_info, sizeof ahd_info);
124 		printf("%s: %s\n", ahd->sc_dev.dv_xname, ahd_info);
125 	}
126 
127 	ahd_intr_enable(ahd, TRUE);
128 
129 	if (ahd->flags & AHD_RESET_BUS_A)
130 		ahd_reset_channel(ahd, 'A', TRUE);
131 
132 	bzero(&saa, sizeof(saa));
133 	saa.saa_sc_link = &ahd->sc_channel;
134 
135 	ahd->sc_child = config_found((void *)&ahd->sc_dev, &saa, scsiprint);
136 
137 	ahd_unlock(ahd, &s);
138 
139 	return (1);
140 
141 }
142 
143 /*
144  * Catch an interrupt from the adapter
145  */
146 int
147 ahd_platform_intr(void *arg)
148 {
149 	struct	ahd_softc *ahd;
150 
151 	/* XXX in ahc there is some bus_dmamap_sync(PREREAD|PREWRITE); */
152 
153 	ahd = (struct ahd_softc *)arg;
154 	return ahd_intr(ahd);
155 }
156 
157 /*
158  * We have an scb which has been processed by the
159  * adaptor, now we look to see how the operation
160  * went.
161  */
162 void
163 ahd_done(struct ahd_softc *ahd, struct scb *scb)
164 {
165 	struct scsi_xfer *xs = scb->xs;
166 	int s;
167 
168 	/* XXX in ahc there is some bus_dmamap_sync(PREREAD|PREWRITE); */
169 
170 	LIST_REMOVE(scb, pending_links);
171 
172 	timeout_del(&xs->stimeout);
173 
174 	if (xs->datalen) {
175 		int op;
176 
177 		if ((xs->flags & SCSI_DATA_IN) != 0)
178 			op = BUS_DMASYNC_POSTREAD;
179 		else
180 			op = BUS_DMASYNC_POSTWRITE;
181 		bus_dmamap_sync(ahd->parent_dmat, scb->dmamap, 0,
182 		    scb->dmamap->dm_mapsize, op);
183 		bus_dmamap_unload(ahd->parent_dmat, scb->dmamap);
184 	}
185 
186 	/* Translate the CAM status code to a SCSI error code. */
187 	switch (xs->error) {
188 	case CAM_SCSI_STATUS_ERROR:
189 	case CAM_REQ_INPROG:
190 	case CAM_REQ_CMP:
191 		switch (xs->status) {
192 		case SCSI_TASKSET_FULL:
193 			xs->error = XS_NO_CCB;
194 			break;
195 		case SCSI_BUSY:
196 			xs->error = XS_BUSY;
197 			break;
198 		case SCSI_CHECK:
199 		case SCSI_TERMINATED:
200 			if ((scb->flags & SCB_SENSE) == 0) {
201 				/* CHECK on CHECK? */
202 				xs->error = XS_DRIVER_STUFFUP;
203 			} else
204 				xs->error = XS_NOERROR;
205 			break;
206 		default:
207 			xs->error = XS_NOERROR;
208 			break;
209 		}
210 		break;
211 	case CAM_BUSY:
212 		xs->error = XS_BUSY;
213 		break;
214 	case CAM_CMD_TIMEOUT:
215 		xs->error = XS_TIMEOUT;
216 		break;
217 	case CAM_BDR_SENT:
218 	case CAM_SCSI_BUS_RESET:
219 		xs->error = XS_RESET;
220 		break;
221 	case CAM_REQUEUE_REQ:
222 		xs->error = XS_NO_CCB;
223 		break;
224 	case CAM_SEL_TIMEOUT:
225 		xs->error = XS_SELTIMEOUT;
226 		break;
227 	default:
228 		xs->error = XS_DRIVER_STUFFUP;
229 		break;
230 	}
231 
232 	if (xs->error != XS_NOERROR) {
233 		/* Don't clobber any existing error state */
234 	} else if ((scb->flags & SCB_SENSE) != 0) {
235 		/*
236 		 * We performed autosense retrieval.
237 		 *
238 		 * Zero any sense not transferred by the
239 		 * device.  The SCSI spec mandates that any
240 		 * untransferred data should be assumed to be
241 		 * zero.  Complete the 'bounce' of sense information
242 		 * through buffers accessible via bus-space by
243 		 * copying it into the clients csio.
244 		 */
245 		memset(&xs->sense, 0, sizeof(struct scsi_sense_data));
246 		memcpy(&xs->sense, ahd_get_sense_buf(ahd, scb),
247 		    sizeof(struct scsi_sense_data));
248 		xs->error = XS_SENSE;
249 	} else if ((scb->flags & SCB_PKT_SENSE) != 0) {
250 		struct scsi_status_iu_header *siu;
251 		u_int32_t len;
252 
253  		siu = (struct scsi_status_iu_header *)scb->sense_data;
254 		len = SIU_SENSE_LENGTH(siu);
255 		memset(&xs->sense, 0, sizeof(xs->sense));
256 		memcpy(&xs->sense, SIU_SENSE_DATA(siu),
257 		    ulmin(len, sizeof(xs->sense)));
258 		xs->error = XS_SENSE;
259 	}
260 
261 	ahd_lock(ahd, &s);
262 	ahd_free_scb(ahd, scb);
263 	scsi_done(xs);
264 	ahd_unlock(ahd, &s);
265 }
266 
267 void
268 ahd_minphys(struct buf *bp, struct scsi_link *sl)
269 {
270 	/*
271 	 * Even though the card can transfer up to 16megs per command
272 	 * we are limited by the number of segments in the dma segment
273 	 * list that we can hold.  The worst case is that all pages are
274 	 * discontinuous physically, hence the "page per segment" limit
275 	 * enforced here.
276 	 */
277 	if (bp->b_bcount > ((AHD_NSEG - 1) * PAGE_SIZE)) {
278 		bp->b_bcount = ((AHD_NSEG - 1) * PAGE_SIZE);
279 	}
280 	minphys(bp);
281 }
282 
283 void
284 ahd_action(struct scsi_xfer *xs)
285 {
286 	struct	ahd_softc *ahd;
287 	struct scb *scb;
288 	struct hardware_scb *hscb;
289 	u_int	target_id;
290 	u_int	our_id;
291 	int	s;
292 	struct	ahd_initiator_tinfo *tinfo;
293 	struct	ahd_tmode_tstate *tstate;
294 	u_int	col_idx;
295 	u_int16_t quirks;
296 
297 	SC_DEBUG(xs->sc_link, SDEV_DB3, ("ahd_action\n"));
298 	ahd = (struct ahd_softc *)xs->sc_link->adapter_softc;
299 
300 	target_id = xs->sc_link->target;
301 	our_id = SCSI_SCSI_ID(ahd, xs->sc_link);
302 
303 	ahd_lock(ahd, &s);
304 	if ((ahd->flags & AHD_INITIATORROLE) == 0) {
305 		xs->error = XS_DRIVER_STUFFUP;
306 		scsi_done(xs);
307 		ahd_unlock(ahd, &s);
308 		return;
309 	}
310 	/*
311 	 * get an scb to use.
312 	 */
313 	tinfo = ahd_fetch_transinfo(ahd, 'A', our_id, target_id, &tstate);
314 
315 	quirks = xs->sc_link->quirks;
316 
317 	if ((quirks & SDEV_NOTAGS) != 0 ||
318 	    (tinfo->curr.ppr_options & MSG_EXT_PPR_PROT_IUS) != 0)
319 		col_idx = AHD_NEVER_COL_IDX;
320 	else
321 		col_idx = AHD_BUILD_COL_IDX(target_id, xs->sc_link->lun);
322 
323 	if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) {
324 		ahd->flags |= AHD_RESOURCE_SHORTAGE;
325 		xs->error = XS_NO_CCB;
326 		scsi_done(xs);
327 		ahd_unlock(ahd, &s);
328 		return;
329 	}
330 	ahd_unlock(ahd, &s);
331 
332 	hscb = scb->hscb;
333 
334 	SC_DEBUG(xs->sc_link, SDEV_DB3, ("start scb(%p)\n", scb));
335 
336 	scb->xs = xs;
337 	timeout_set(&xs->stimeout, ahd_timeout, scb);
338 
339 	/*
340 	 * Put all the arguments for the xfer in the scb
341 	 */
342 	hscb->control = 0;
343 	hscb->scsiid = BUILD_SCSIID(ahd, xs->sc_link, target_id, our_id);
344 	hscb->lun = xs->sc_link->lun;
345 	if (xs->xs_control & XS_CTL_RESET) {
346 		hscb->cdb_len = 0;
347 		scb->flags |= SCB_DEVICE_RESET;
348 		hscb->control |= MK_MESSAGE;
349 		hscb->task_management = SIU_TASKMGMT_LUN_RESET;
350 		ahd_execute_scb(scb, NULL, 0);
351 	} else {
352 		hscb->task_management = 0;
353 		ahd_setup_data(ahd, xs, scb);
354 	}
355 }
356 
357 void
358 ahd_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments)
359 {
360 	struct	scb *scb;
361 	struct	scsi_xfer *xs;
362 	struct	ahd_softc *ahd;
363 	struct	ahd_initiator_tinfo *tinfo;
364 	struct	ahd_tmode_tstate *tstate;
365 	u_int	mask;
366 	int	s;
367 
368 	scb = (struct scb *)arg;
369 	xs = scb->xs;
370 	xs->error = CAM_REQ_INPROG;
371 	xs->status = 0;
372 	ahd = (struct ahd_softc *)xs->sc_link->adapter_softc;
373 
374 	if (nsegments != 0) {
375 		void *sg;
376 		int op;
377 		u_int i;
378 
379 		ahd_setup_data_scb(ahd, scb);
380 
381 		/* Copy the segments into our SG list */
382 		for (i = nsegments, sg = scb->sg_list; i > 0; i--) {
383 
384 			sg = ahd_sg_setup(ahd, scb, sg, dm_segs->ds_addr,
385 					  dm_segs->ds_len,
386 					  /*last*/i == 1);
387 			dm_segs++;
388 		}
389 
390 		if ((xs->flags & SCSI_DATA_IN) != 0)
391 			op = BUS_DMASYNC_PREREAD;
392 		else
393 			op = BUS_DMASYNC_PREWRITE;
394 
395 		bus_dmamap_sync(ahd->parent_dmat, scb->dmamap, 0,
396 				scb->dmamap->dm_mapsize, op);
397 
398 	}
399 
400 	ahd_lock(ahd, &s);
401 
402 	/*
403 	 * Last time we need to check if this SCB needs to
404 	 * be aborted.
405 	 */
406 	if (xs->flags & ITSDONE) {
407 		if (nsegments != 0)
408 			bus_dmamap_unload(ahd->parent_dmat,
409 					  scb->dmamap);
410 		ahd_free_scb(ahd, scb);
411 		ahd_unlock(ahd, &s);
412 		return;
413 	}
414 
415 	tinfo = ahd_fetch_transinfo(ahd, SCSIID_CHANNEL(ahd, scb->hscb->scsiid),
416 				    SCSIID_OUR_ID(scb->hscb->scsiid),
417 				    SCSIID_TARGET(ahd, scb->hscb->scsiid),
418 				    &tstate);
419 
420 	mask = SCB_GET_TARGET_MASK(ahd, scb);
421 
422 	if ((tstate->discenable & mask) != 0)
423 		scb->hscb->control |= DISCENB;
424 
425 	if ((tstate->tagenable & mask) != 0)
426 		scb->hscb->control |= TAG_ENB;
427 
428 	if ((tinfo->curr.ppr_options & MSG_EXT_PPR_PROT_IUS) != 0) {
429 		scb->flags |= SCB_PACKETIZED;
430 		if (scb->hscb->task_management != 0)
431 			scb->hscb->control &= ~MK_MESSAGE;
432 	}
433 
434 	if ((tstate->auto_negotiate & mask) != 0) {
435 		scb->flags |= SCB_AUTO_NEGOTIATE;
436 		scb->hscb->control |= MK_MESSAGE;
437 	}
438 
439 	/* XXX with ahc there was some bus_dmamap_sync(PREREAD|PREWRITE); */
440 
441 	LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links);
442 
443 	if (!(xs->flags & SCSI_POLL))
444 		timeout_add_msec(&xs->stimeout, xs->timeout);
445 
446 	scb->flags |= SCB_ACTIVE;
447 
448 	if ((scb->flags & SCB_TARGET_IMMEDIATE) != 0) {
449 		/* Define a mapping from our tag to the SCB. */
450 		ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb;
451 		ahd_pause(ahd);
452 		ahd_set_scbptr(ahd, SCB_GET_TAG(scb));
453 		ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_TARG);
454 		ahd_unpause(ahd);
455 	} else {
456 		ahd_queue_scb(ahd, scb);
457 	}
458 
459 	if (!(xs->flags & SCSI_POLL)) {
460 		int target = xs->sc_link->target;
461 		int lun = SCB_GET_LUN(scb);
462 
463 		if (ahd->inited_target[target] == 0) {
464 			struct  ahd_devinfo devinfo;
465 
466 			ahd_adapter_req_set_xfer_mode(ahd, scb);
467 			ahd_compile_devinfo(&devinfo, ahd->our_id, target, lun,
468 			    'A', /*XXX milos*/ROLE_UNKNOWN);
469 			ahd_scb_devinfo(ahd, &devinfo, scb);
470 			ahd_update_neg_request(ahd, &devinfo, tstate, tinfo,
471 				AHD_NEG_IF_NON_ASYNC);
472 			ahd->inited_target[target] = 1;
473 		}
474 
475 		ahd_unlock(ahd, &s);
476 		return;
477 	}
478 
479 	/*
480 	 * If we can't use interrupts, poll for completion
481 	 */
482 	SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_poll\n"));
483 
484 	do {
485 		if (ahd_poll(ahd, xs->timeout)) {
486 			if (!(xs->flags & SCSI_SILENT))
487 				printf("cmd fail\n");
488 			ahd_timeout(scb);
489 			break;
490 		}
491 	} while (!(xs->flags & ITSDONE));
492 
493 	ahd_unlock(ahd, &s);
494 }
495 
496 int
497 ahd_poll(struct ahd_softc *ahd, int wait)
498 {
499 	while (--wait) {
500 		DELAY(1000);
501 		if (ahd_inb(ahd, INTSTAT) & INT_PEND)
502 			break;
503 	}
504 
505 	if (wait == 0) {
506 		printf("%s: board is not responding\n", ahd_name(ahd));
507 		return (EIO);
508 	}
509 
510 	ahd_intr((void *)ahd);
511 	return (0);
512 }
513 
514 void
515 ahd_setup_data(struct ahd_softc *ahd, struct scsi_xfer *xs,
516 	       struct scb *scb)
517 {
518 	struct hardware_scb *hscb;
519 	int s;
520 
521 	hscb = scb->hscb;
522 	xs->resid = xs->status = 0;
523 	xs->error = CAM_REQ_INPROG;
524 
525 	hscb->cdb_len = xs->cmdlen;
526 	if (hscb->cdb_len > MAX_CDB_LEN) {
527 		ahd_lock(ahd, &s);
528 		ahd_free_scb(ahd, scb);
529 		xs->error = XS_DRIVER_STUFFUP;
530 		scsi_done(xs);
531 		ahd_unlock(ahd, &s);
532 		return;
533 	}
534 
535 	memcpy(hscb->shared_data.idata.cdb, xs->cmd, hscb->cdb_len);
536 
537 	/* Only use S/G if there is a transfer */
538 	if (xs->datalen) {
539 		int error;
540 
541 		error = bus_dmamap_load(ahd->parent_dmat,
542 					scb->dmamap, xs->data,
543 					xs->datalen, NULL,
544 					((xs->flags & SCSI_NOSLEEP) ?
545 					BUS_DMA_NOWAIT : BUS_DMA_WAITOK) |
546 					BUS_DMA_STREAMING |
547 					((xs->flags & XS_CTL_DATA_IN) ?
548 					BUS_DMA_READ : BUS_DMA_WRITE));
549 		if (error) {
550 #ifdef AHD_DEBUG
551 			printf("%s: in ahd_setup_data(): bus_dmamap_load() "
552 			    "= %d\n", ahd_name(ahd), error);
553 #endif
554 			ahd_lock(ahd, &s);
555 			ahd_free_scb(ahd, scb);
556 			xs->error = XS_NO_CCB;
557 			scsi_done(xs);
558 			ahd_unlock(ahd, &s);
559 			return;
560 		}
561 		ahd_execute_scb(scb, scb->dmamap->dm_segs,
562 		    scb->dmamap->dm_nsegs);
563 	} else {
564 		ahd_execute_scb(scb, NULL, 0);
565 	}
566 }
567 
568 void
569 ahd_platform_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
570     ahd_queue_alg alg)
571 {
572 	struct ahd_tmode_tstate *tstate;
573 
574 	ahd_fetch_transinfo(ahd, devinfo->channel, devinfo->our_scsiid,
575 	    devinfo->target, &tstate);
576 
577 	if (alg != AHD_QUEUE_NONE)
578 		tstate->tagenable |= devinfo->target_mask;
579 	else
580 		tstate->tagenable &= ~devinfo->target_mask;
581 }
582 
583 int
584 ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg)
585 {
586 	if (sizeof(struct ahd_platform_data) > 0) {
587 		ahd->platform_data = malloc(sizeof(struct ahd_platform_data),
588 		    M_DEVBUF, M_NOWAIT | M_ZERO);
589 		if (ahd->platform_data == NULL)
590 			return (ENOMEM);
591 	}
592 
593 	return (0);
594 }
595 
596 void
597 ahd_platform_free(struct ahd_softc *ahd)
598 {
599 	if (sizeof(struct ahd_platform_data) > 0)
600 		free(ahd->platform_data, M_DEVBUF);
601 }
602 
603 int
604 ahd_softc_comp(struct ahd_softc *lahd, struct ahd_softc *rahd)
605 {
606 	/* We don't sort softcs under OpenBSD so report equal always */
607 	return (0);
608 }
609 
610 int
611 ahd_detach(struct device *self, int flags)
612 {
613 	int rv = 0;
614 
615 	struct ahd_softc *ahd = (struct ahd_softc*)self;
616 
617 	if (ahd->sc_child != NULL)
618 		rv = config_detach((void *)ahd->sc_child, flags);
619 
620 	if (ahd->shutdown_hook != NULL)
621 		shutdownhook_disestablish(ahd->shutdown_hook);
622 
623 	ahd_free(ahd);
624 
625 	return rv;
626 }
627 
628 void
629 ahd_adapter_req_set_xfer_mode(struct ahd_softc *ahd, struct scb *scb)
630 {
631 	struct ahd_initiator_tinfo *tinfo;
632 	struct ahd_tmode_tstate *tstate;
633 	int target_id, our_id;
634 	struct ahd_devinfo devinfo;
635 	u_int16_t quirks;
636 	u_int width, ppr_options, period, offset;
637 	int s;
638 
639 	target_id = scb->xs->sc_link->target;
640 	our_id = SCSI_SCSI_ID(ahd, scb->xs->sc_link);
641 
642 	s = splbio();
643 
644 	quirks = scb->xs->sc_link->quirks;
645 	tinfo = ahd_fetch_transinfo(ahd, 'A', our_id, target_id, &tstate);
646 	ahd_compile_devinfo(&devinfo, our_id, target_id, 0, 'A',
647 	    ROLE_INITIATOR);
648 
649 	tstate->discenable |= (ahd->user_discenable & devinfo.target_mask);
650 
651 	if (quirks & SDEV_NOTAGS)
652 		tstate->tagenable &= ~devinfo.target_mask;
653 	else if (ahd->user_tagenable & devinfo.target_mask)
654 		tstate->tagenable |= devinfo.target_mask;
655 
656 	if (quirks & SDEV_NOWIDE)
657 		width = MSG_EXT_WDTR_BUS_8_BIT;
658 	else
659 		width = MSG_EXT_WDTR_BUS_16_BIT;
660 
661 	ahd_validate_width(ahd, NULL, &width, ROLE_UNKNOWN);
662 	if (width > tinfo->user.width)
663 		width = tinfo->user.width;
664 	ahd_set_width(ahd, &devinfo, width, AHD_TRANS_GOAL, FALSE);
665 
666 	if (quirks & SDEV_NOSYNC) {
667 		period = 0;
668 		offset = 0;
669 	} else {
670 		period = tinfo->user.period;
671 		offset = tinfo->user.offset;
672 	}
673 
674 	/* XXX Look at saved INQUIRY flags for PPR capabilities XXX */
675 	ppr_options = tinfo->user.ppr_options;
676 	/* XXX Other reasons to avoid ppr? XXX */
677 	if (width < MSG_EXT_WDTR_BUS_16_BIT)
678 		ppr_options = 0;
679 
680 	if ((tstate->discenable & devinfo.target_mask) == 0 ||
681 	    (tstate->tagenable & devinfo.target_mask) == 0)
682 		ppr_options &= ~MSG_EXT_PPR_PROT_IUS;
683 
684 	ahd_find_syncrate(ahd, &period, &ppr_options, AHD_SYNCRATE_MAX);
685 	ahd_validate_offset(ahd, NULL, period, &offset, width, ROLE_UNKNOWN);
686 
687 	if (offset == 0) {
688 		period = 0;
689 		ppr_options = 0;
690 	}
691 
692 	if (ppr_options != 0 && tinfo->user.transport_version >= 3) {
693 		tinfo->goal.transport_version = tinfo->user.transport_version;
694 		tinfo->curr.transport_version = tinfo->user.transport_version;
695 	}
696 
697 	ahd_set_syncrate(ahd, &devinfo, period, offset, ppr_options,
698 		AHD_TRANS_GOAL, FALSE);
699 
700 	splx(s);
701 }
702 
703 void
704 aic_timer_reset(aic_timer_t *timer, u_int msec, ahd_callback_t *func,
705     void *arg)
706 {
707 	uint64_t ticks;
708 
709 	ticks = msec;
710 	ticks *= hz;
711 	ticks /= 1000;
712 	callout_reset(timer, ticks, func, arg);
713 }
714 
715 void
716 aic_scb_timer_reset(struct scb *scb, u_int msec)
717 {
718 	uint64_t ticks;
719 
720 	ticks = msec;
721 	ticks *= hz;
722 	ticks /= 1000;
723 	if (!(scb->xs->xs_control & XS_CTL_POLL))
724 		callout_reset(&scb->xs->xs_callout, ticks, ahd_timeout, scb);
725 }
726 
727 void
728 ahd_flush_device_writes(struct ahd_softc *ahd)
729 {
730 	/* XXX Is this sufficient for all architectures??? */
731 	ahd_inb(ahd, INTSTAT);
732 }
733 
734 void
735 aic_platform_scb_free(struct ahd_softc *ahd, struct scb *scb)
736 {
737 	int s;
738 
739 	ahd_lock(ahd, &s);
740 
741 	if ((ahd->flags & AHD_RESOURCE_SHORTAGE) != 0) {
742 		ahd->flags &= ~AHD_RESOURCE_SHORTAGE;
743 	}
744 
745 	if (!cold) {
746 		/* we are no longer in autoconf */
747 		timeout_del(&scb->xs->stimeout);
748 	}
749 
750 	ahd_unlock(ahd, &s);
751 }
752 
753 void
754 ahd_print_path(struct ahd_softc *ahd, struct scb *scb)
755 {
756 	sc_print_addr(scb->xs->sc_link);
757 }
758 
759 void
760 ahd_platform_dump_card_state(struct ahd_softc *ahd)
761 {
762 	/* Nothing to do here for OpenBSD */
763 	printf("FEATURES = 0x%x, FLAGS = 0x%x, CHIP = 0x%x BUGS =0x%x\n",
764 		ahd->features, ahd->flags, ahd->chip, ahd->bugs);
765 }
766 
767 void
768 ahd_platform_flushwork(struct ahd_softc *ahd)
769 {
770 }
771