Home | History | Annotate | Line # | Download | only in ic
aic79xx_osm.c revision 1.14
      1  1.14   bouyer /*	$NetBSD: aic79xx_osm.c,v 1.14 2005/12/05 18:29:45 bouyer Exp $	*/
      2   1.1     fvdl 
      3   1.1     fvdl /*
      4   1.1     fvdl  * Bus independent NetBSD shim for the aic7xxx based adaptec SCSI controllers
      5   1.1     fvdl  *
      6   1.1     fvdl  * Copyright (c) 1994-2002 Justin T. Gibbs.
      7   1.1     fvdl  * Copyright (c) 2001-2002 Adaptec Inc.
      8   1.1     fvdl  * All rights reserved.
      9   1.1     fvdl  *
     10   1.1     fvdl  * Redistribution and use in source and binary forms, with or without
     11   1.1     fvdl  * modification, are permitted provided that the following conditions
     12   1.1     fvdl  * are met:
     13   1.1     fvdl  * 1. Redistributions of source code must retain the above copyright
     14   1.1     fvdl  *    notice, this list of conditions, and the following disclaimer,
     15   1.1     fvdl  *    without modification.
     16   1.1     fvdl  * 2. The name of the author may not be used to endorse or promote products
     17   1.1     fvdl  *    derived from this software without specific prior written permission.
     18   1.1     fvdl  *
     19   1.1     fvdl  * Alternatively, this software may be distributed under the terms of the
     20   1.1     fvdl  * GNU Public License ("GPL").
     21   1.1     fvdl  *
     22   1.1     fvdl  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     23   1.1     fvdl  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24   1.1     fvdl  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25   1.1     fvdl  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
     26   1.1     fvdl  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27   1.1     fvdl  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28   1.1     fvdl  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29   1.1     fvdl  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30   1.1     fvdl  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31   1.1     fvdl  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32   1.1     fvdl  * SUCH DAMAGE.
     33   1.1     fvdl  *
     34   1.1     fvdl  * //depot/aic7xxx/freebsd/dev/aic7xxx/aic79xx_osm.c#26 $
     35   1.1     fvdl  *
     36   1.5  thorpej  * $FreeBSD: src/sys/dev/aic7xxx/aic79xx_osm.c,v 1.11 2003/05/04 00:20:07 gibbs Exp $
     37   1.1     fvdl  */
     38   1.1     fvdl /*
     39   1.1     fvdl  * Ported from FreeBSD by Pascal Renauld, Network Storage Solutions, Inc.
     40   1.1     fvdl  * - April 2003
     41   1.1     fvdl  */
     42   1.4    lukem 
     43   1.4    lukem #include <sys/cdefs.h>
     44  1.14   bouyer __KERNEL_RCSID(0, "$NetBSD: aic79xx_osm.c,v 1.14 2005/12/05 18:29:45 bouyer Exp $");
     45   1.1     fvdl 
     46   1.1     fvdl #include <dev/ic/aic79xx_osm.h>
     47   1.1     fvdl #include <dev/ic/aic7xxx_cam.h>
     48   1.1     fvdl #include <dev/ic/aic79xx_inline.h>
     49   1.1     fvdl 
     50   1.1     fvdl #ifndef AHD_TMODE_ENABLE
     51   1.1     fvdl #define AHD_TMODE_ENABLE 0
     52   1.1     fvdl #endif
     53   1.1     fvdl 
     54  1.12    perry static int	ahd_ioctl(struct scsipi_channel *channel, u_long cmd,
     55   1.1     fvdl 			  caddr_t addr, int flag, struct proc *p);
     56  1.12    perry static void	ahd_action(struct scsipi_channel *chan,
     57   1.1     fvdl 			   scsipi_adapter_req_t req, void *arg);
     58   1.1     fvdl static void	ahd_execute_scb(void *arg, bus_dma_segment_t *dm_segs,
     59   1.1     fvdl 				int nsegments);
     60   1.1     fvdl static int	ahd_poll(struct ahd_softc *ahd, int wait);
     61   1.1     fvdl static void	ahd_setup_data(struct ahd_softc *ahd, struct scsipi_xfer *xs,
     62   1.1     fvdl 			       struct scb *scb);
     63   1.1     fvdl 
     64   1.1     fvdl #if NOT_YET
     65   1.1     fvdl static void	ahd_set_recoveryscb(struct ahd_softc *ahd, struct scb *scb);
     66   1.1     fvdl #endif
     67   1.1     fvdl 
     68   1.1     fvdl /*
     69   1.1     fvdl  * Attach all the sub-devices we can find
     70   1.1     fvdl  */
     71   1.1     fvdl int
     72   1.1     fvdl ahd_attach(struct ahd_softc *ahd)
     73   1.1     fvdl {
     74   1.1     fvdl 	int 	s;
     75   1.1     fvdl 	char	ahd_info[256];
     76   1.1     fvdl 
     77   1.8   itojun 	ahd_controller_info(ahd, ahd_info, sizeof(ahd_info));
     78   1.1     fvdl         printf("%s: %s\n", ahd->sc_dev.dv_xname, ahd_info);
     79   1.1     fvdl 
     80   1.1     fvdl         ahd_lock(ahd, &s);
     81   1.1     fvdl 
     82   1.1     fvdl 	ahd->sc_adapter.adapt_dev = &ahd->sc_dev;
     83   1.1     fvdl 	ahd->sc_adapter.adapt_nchannels = 1;
     84  1.12    perry 
     85  1.13   bouyer 	ahd->sc_adapter.adapt_openings = ahd->scb_data.numscbs - 1;
     86   1.1     fvdl 	ahd->sc_adapter.adapt_max_periph = 32;
     87   1.1     fvdl 
     88   1.1     fvdl 	ahd->sc_adapter.adapt_ioctl = ahd_ioctl;
     89   1.1     fvdl 	ahd->sc_adapter.adapt_minphys = ahd_minphys;
     90   1.1     fvdl 	ahd->sc_adapter.adapt_request = ahd_action;
     91   1.1     fvdl 
     92   1.1     fvdl 	ahd->sc_channel.chan_adapter = &ahd->sc_adapter;
     93   1.1     fvdl         ahd->sc_channel.chan_bustype = &scsi_bustype;
     94   1.1     fvdl         ahd->sc_channel.chan_channel = 0;
     95   1.1     fvdl         ahd->sc_channel.chan_ntargets = AHD_NUM_TARGETS;
     96   1.1     fvdl         ahd->sc_channel.chan_nluns = 8 /*AHD_NUM_LUNS*/;
     97   1.1     fvdl         ahd->sc_channel.chan_id = ahd->our_id;
     98  1.13   bouyer         ahd->sc_channel.chan_flags |= SCSIPI_CHAN_CANGROW;
     99   1.1     fvdl 
    100   1.1     fvdl 	ahd->sc_child = config_found((void *)ahd, &ahd->sc_channel, scsiprint);
    101   1.1     fvdl 
    102   1.1     fvdl 	ahd_intr_enable(ahd, TRUE);
    103   1.1     fvdl 
    104   1.3     fvdl 	if (ahd->flags & AHD_RESET_BUS_A)
    105   1.3     fvdl 		ahd_reset_channel(ahd, 'A', TRUE);
    106   1.3     fvdl 
    107   1.1     fvdl         ahd_unlock(ahd, &s);
    108   1.1     fvdl 
    109   1.1     fvdl 	return (1);
    110   1.1     fvdl }
    111   1.1     fvdl 
    112   1.1     fvdl static int
    113  1.12    perry ahd_ioctl(struct scsipi_channel *channel, u_long cmd,
    114   1.1     fvdl 	  caddr_t addr, int flag, struct proc *p)
    115   1.1     fvdl {
    116   1.1     fvdl         struct ahd_softc *ahd = (void *)channel->chan_adapter->adapt_dev;
    117   1.1     fvdl         int s, ret = ENOTTY;
    118   1.1     fvdl 
    119   1.1     fvdl         switch (cmd) {
    120   1.1     fvdl         case SCBUSIORESET:
    121   1.1     fvdl                 s = splbio();
    122   1.1     fvdl                 ahd_reset_channel(ahd, channel->chan_channel == 1 ? 'B' : 'A', TRUE);
    123   1.1     fvdl                 splx(s);
    124   1.1     fvdl                 ret = 0;
    125   1.1     fvdl                 break;
    126   1.1     fvdl         default:
    127   1.1     fvdl                 break;
    128   1.1     fvdl         }
    129   1.1     fvdl 
    130   1.1     fvdl         return ret;
    131   1.1     fvdl }
    132   1.1     fvdl 
    133   1.1     fvdl /*
    134   1.1     fvdl  * Catch an interrupt from the adapter
    135   1.1     fvdl  */
    136   1.1     fvdl void
    137   1.1     fvdl ahd_platform_intr(void *arg)
    138   1.1     fvdl {
    139   1.1     fvdl 	struct	ahd_softc *ahd;
    140  1.12    perry 
    141  1.12    perry 	ahd = (struct ahd_softc *)arg;
    142   1.1     fvdl 
    143   1.1     fvdl 	printf("%s; ahd_platform_intr\n", ahd_name(ahd));
    144   1.1     fvdl 
    145   1.1     fvdl 	ahd_intr(ahd);
    146   1.1     fvdl }
    147   1.1     fvdl 
    148   1.1     fvdl /*
    149   1.1     fvdl  * We have an scb which has been processed by the
    150   1.1     fvdl  * adaptor, now we look to see how the operation * went.
    151   1.1     fvdl  */
    152   1.1     fvdl void
    153   1.1     fvdl ahd_done(struct ahd_softc *ahd, struct scb *scb)
    154   1.1     fvdl {
    155   1.1     fvdl 	struct scsipi_xfer	*xs;
    156   1.1     fvdl 	struct scsipi_periph	*periph;
    157   1.1     fvdl 	int			s;
    158   1.1     fvdl 
    159   1.1     fvdl 	LIST_REMOVE(scb, pending_links);
    160   1.1     fvdl 
    161   1.1     fvdl 	xs = scb->xs;
    162   1.1     fvdl 	periph = xs->xs_periph;
    163   1.1     fvdl 
    164   1.1     fvdl 	callout_stop(&scb->xs->xs_callout);
    165   1.1     fvdl 
    166   1.1     fvdl 	if (xs->datalen) {
    167   1.1     fvdl 		int op;
    168   1.1     fvdl 
    169   1.1     fvdl 		if (xs->xs_control & XS_CTL_DATA_IN)
    170   1.1     fvdl 		  op = BUS_DMASYNC_POSTREAD;
    171   1.1     fvdl 		else
    172   1.1     fvdl 		  op = BUS_DMASYNC_POSTWRITE;
    173   1.1     fvdl 
    174   1.1     fvdl 		bus_dmamap_sync(ahd->parent_dmat, scb->dmamap, 0,
    175   1.1     fvdl 				scb->dmamap->dm_mapsize, op);
    176   1.1     fvdl                 bus_dmamap_unload(ahd->parent_dmat, scb->dmamap);
    177   1.1     fvdl         }
    178   1.1     fvdl 
    179   1.1     fvdl 	/*
    180   1.1     fvdl 	 * If the recovery SCB completes, we have to be
    181   1.1     fvdl 	 * out of our timeout.
    182   1.1     fvdl 	 */
    183   1.1     fvdl 	if ((scb->flags & SCB_RECOVERY_SCB) != 0) {
    184   1.1     fvdl 		struct	scb *list_scb;
    185   1.1     fvdl 
    186   1.1     fvdl 		/*
    187   1.1     fvdl 		 * We were able to complete the command successfully,
    188   1.1     fvdl 		 * so reinstate the timeouts for all other pending
    189   1.1     fvdl 		 * commands.
    190   1.1     fvdl 		 */
    191   1.1     fvdl 		LIST_FOREACH(list_scb, &ahd->pending_scbs, pending_links) {
    192   1.1     fvdl 			struct scsipi_xfer	*txs = list_scb->xs;
    193  1.12    perry 
    194   1.1     fvdl 			if (!(txs->xs_control & XS_CTL_POLL)) {
    195   1.1     fvdl                                 callout_reset(&txs->xs_callout,
    196   1.1     fvdl                                     (txs->timeout > 1000000) ?
    197   1.1     fvdl                                     (txs->timeout / 1000) * hz :
    198   1.1     fvdl                                     (txs->timeout * hz) / 1000,
    199   1.1     fvdl                                     ahd_timeout, list_scb);
    200   1.1     fvdl                         }
    201   1.1     fvdl 		}
    202   1.1     fvdl 
    203   1.1     fvdl 		if (ahd_get_transaction_status(scb) != XS_NOERROR)
    204   1.1     fvdl 		  ahd_set_transaction_status(scb, XS_TIMEOUT);
    205   1.1     fvdl                 scsipi_printaddr(xs->xs_periph);
    206  1.12    perry 		printf("%s: no longer in timeout, status = %x\n",
    207   1.1     fvdl 		       ahd_name(ahd), xs->status);
    208   1.1     fvdl 	}
    209   1.1     fvdl 
    210   1.1     fvdl 	if (xs->error != XS_NOERROR) {
    211   1.1     fvdl                 /* Don't clobber any existing error state */
    212   1.1     fvdl 	} else if ((xs->status == SCSI_STATUS_BUSY) ||
    213   1.1     fvdl 		   (xs->status == SCSI_STATUS_QUEUE_FULL)) {
    214   1.1     fvdl 	  	ahd_set_transaction_status(scb, XS_BUSY);
    215  1.12    perry 		printf("%s: drive (ID %d, LUN %d) queue full (SCB 0x%x)\n",
    216   1.1     fvdl 		       ahd_name(ahd), SCB_GET_TARGET(ahd,scb), SCB_GET_LUN(scb), SCB_GET_TAG(scb));
    217   1.1     fvdl         } else if ((scb->flags & SCB_SENSE) != 0) {
    218   1.1     fvdl                 /*
    219   1.1     fvdl                  * We performed autosense retrieval.
    220   1.1     fvdl                  *
    221   1.1     fvdl                  * zero the sense data before having
    222   1.1     fvdl                  * the drive fill it.  The SCSI spec mandates
    223   1.1     fvdl                  * that any untransferred data should be
    224   1.1     fvdl                  * assumed to be zero.  Complete the 'bounce'
    225   1.1     fvdl                  * of sense information through buffers accessible
    226   1.1     fvdl                  * via bus-space by copying it into the clients
    227   1.1     fvdl                  * csio.
    228   1.1     fvdl                  */
    229   1.1     fvdl                 memset(&xs->sense.scsi_sense, 0, sizeof(xs->sense.scsi_sense));
    230   1.1     fvdl                 memcpy(&xs->sense.scsi_sense, ahd_get_sense_buf(ahd, scb),
    231  1.11  thorpej 		       sizeof(struct scsi_sense_data));
    232  1.12    perry 
    233   1.1     fvdl                 ahd_set_transaction_status(scb, XS_SENSE);
    234   1.1     fvdl         } else if ((scb->flags & SCB_PKT_SENSE) != 0) {
    235   1.1     fvdl 		struct scsi_status_iu_header *siu;
    236   1.1     fvdl 		u_int sense_len;
    237   1.9     fvdl #ifdef AHD_DEBUG
    238   1.1     fvdl 		int i;
    239   1.9     fvdl #endif
    240   1.1     fvdl 		/*
    241   1.1     fvdl 		 * Copy only the sense data into the provided buffer.
    242   1.1     fvdl 		 */
    243   1.1     fvdl 		siu = (struct scsi_status_iu_header *)scb->sense_data;
    244   1.1     fvdl 		sense_len = MIN(scsi_4btoul(siu->sense_length),
    245  1.10     fvdl 				sizeof(xs->sense.scsi_sense));
    246   1.1     fvdl 		memset(&xs->sense.scsi_sense, 0, sizeof(xs->sense.scsi_sense));
    247  1.12    perry 		memcpy(&xs->sense.scsi_sense,
    248   1.1     fvdl 		       scb->sense_data + SIU_SENSE_OFFSET(siu), sense_len);
    249   1.9     fvdl #ifdef AHD_DEBUG
    250   1.1     fvdl 		printf("Copied %d bytes of sense data offset %d:", sense_len,
    251   1.1     fvdl 		       SIU_SENSE_OFFSET(siu));
    252   1.1     fvdl 		for (i = 0; i < sense_len; i++)
    253   1.1     fvdl 			printf(" 0x%x", ((uint8_t *)&xs->sense.scsi_sense)[i]);
    254   1.1     fvdl 		printf("\n");
    255   1.9     fvdl #endif
    256   1.1     fvdl                 ahd_set_transaction_status(scb, XS_SENSE);
    257   1.1     fvdl 	}
    258   1.1     fvdl 
    259   1.1     fvdl 	if (scb->flags & SCB_FREEZE_QUEUE) {
    260   1.1     fvdl 	        scsipi_periph_thaw(periph, 1);
    261   1.1     fvdl                 scb->flags &= ~SCB_FREEZE_QUEUE;
    262   1.1     fvdl         }
    263   1.1     fvdl 
    264   1.1     fvdl         if (scb->flags & SCB_REQUEUE)
    265   1.1     fvdl                 ahd_set_transaction_status(scb, XS_REQUEUE);
    266   1.1     fvdl 
    267  1.12    perry         ahd_lock(ahd, &s);
    268   1.1     fvdl         ahd_free_scb(ahd, scb);
    269   1.1     fvdl         ahd_unlock(ahd, &s);
    270   1.1     fvdl 
    271   1.1     fvdl         scsipi_done(xs);
    272   1.1     fvdl }
    273   1.1     fvdl 
    274   1.1     fvdl static void
    275   1.1     fvdl ahd_action(struct scsipi_channel *chan, scsipi_adapter_req_t req, void *arg)
    276   1.1     fvdl {
    277   1.1     fvdl         struct ahd_softc *ahd;
    278   1.1     fvdl 	struct ahd_initiator_tinfo *tinfo;
    279   1.1     fvdl 	struct ahd_tmode_tstate *tstate;
    280   1.1     fvdl 
    281   1.1     fvdl 	ahd = (void *)chan->chan_adapter->adapt_dev;
    282   1.1     fvdl 
    283   1.1     fvdl 	switch(req) {
    284   1.1     fvdl 
    285   1.1     fvdl 	case ADAPTER_REQ_RUN_XFER:
    286   1.1     fvdl 	  {
    287   1.1     fvdl 		struct scsipi_xfer *xs;
    288   1.1     fvdl         	struct scsipi_periph *periph;
    289   1.1     fvdl 	        struct scb *scb;
    290   1.1     fvdl         	struct hardware_scb *hscb;
    291   1.1     fvdl 		u_int target_id;
    292   1.1     fvdl 		u_int our_id;
    293   1.1     fvdl 		u_int col_idx;
    294   1.1     fvdl 		char channel;
    295   1.1     fvdl 		int s;
    296   1.1     fvdl 
    297   1.1     fvdl 	  	xs = arg;
    298   1.1     fvdl                 periph = xs->xs_periph;
    299   1.1     fvdl 
    300   1.1     fvdl                 SC_DEBUG(periph, SCSIPI_DB3, ("ahd_action\n"));
    301   1.1     fvdl 
    302   1.1     fvdl 		target_id = periph->periph_target;
    303  1.12    perry                 our_id = ahd->our_id;
    304   1.1     fvdl                 channel = (chan->chan_channel == 1) ? 'B' : 'A';
    305   1.1     fvdl 
    306   1.1     fvdl                 /*
    307   1.1     fvdl 		 * get an scb to use.
    308   1.1     fvdl 		 */
    309   1.1     fvdl 		ahd_lock(ahd, &s);
    310   1.1     fvdl 		tinfo = ahd_fetch_transinfo(ahd, channel, our_id,
    311   1.1     fvdl 					    target_id, &tstate);
    312   1.1     fvdl 
    313   1.6     fvdl 		if (xs->xs_tag_type != 0 ||
    314   1.6     fvdl 		    (tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0)
    315   1.6     fvdl 			col_idx = AHD_NEVER_COL_IDX;
    316   1.6     fvdl 		else
    317   1.6     fvdl 			col_idx = AHD_BUILD_COL_IDX(target_id,
    318   1.6     fvdl 			    periph->periph_lun);
    319   1.1     fvdl 
    320   1.1     fvdl 		if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) {
    321   1.1     fvdl 			xs->error = XS_RESOURCE_SHORTAGE;
    322   1.1     fvdl 			ahd_unlock(ahd, &s);
    323   1.1     fvdl 			scsipi_done(xs);
    324   1.1     fvdl 			return;
    325   1.1     fvdl 		}
    326   1.1     fvdl 		ahd_unlock(ahd, &s);
    327   1.1     fvdl 
    328   1.1     fvdl 		hscb = scb->hscb;
    329   1.1     fvdl 
    330   1.1     fvdl 		SC_DEBUG(periph, SCSIPI_DB3, ("start scb(%p)\n", scb));
    331   1.1     fvdl 		scb->xs = xs;
    332   1.1     fvdl 
    333   1.1     fvdl 		/*
    334   1.1     fvdl 		 * Put all the arguments for the xfer in the scb
    335   1.1     fvdl 		 */
    336   1.1     fvdl 		hscb->control = 0;
    337   1.1     fvdl 		hscb->scsiid = BUILD_SCSIID(ahd, sim, target_id, our_id);
    338   1.1     fvdl 		hscb->lun = periph->periph_lun;
    339   1.1     fvdl 		if (xs->xs_control & XS_CTL_RESET) {
    340   1.1     fvdl 			hscb->cdb_len = 0;
    341   1.1     fvdl 			scb->flags |= SCB_DEVICE_RESET;
    342   1.1     fvdl 			hscb->control |= MK_MESSAGE;
    343   1.1     fvdl 			hscb->task_management = SIU_TASKMGMT_LUN_RESET;
    344   1.1     fvdl 			ahd_execute_scb(scb, NULL, 0);
    345   1.1     fvdl 		} else {
    346   1.1     fvdl 			hscb->task_management = 0;
    347   1.1     fvdl 		}
    348   1.1     fvdl 
    349   1.1     fvdl 		ahd_setup_data(ahd, xs, scb);
    350   1.1     fvdl 		break;
    351   1.1     fvdl 	  }
    352   1.1     fvdl 
    353   1.1     fvdl 	case ADAPTER_REQ_GROW_RESOURCES:
    354  1.14   bouyer #ifdef AHC_DEBUG
    355   1.1     fvdl 		printf("%s: ADAPTER_REQ_GROW_RESOURCES\n", ahd_name(ahd));
    356  1.14   bouyer #endif
    357  1.13   bouyer 		chan->chan_adapter->adapt_openings += ahd_alloc_scbs(ahd);
    358  1.13   bouyer 		if (ahd->scb_data.numscbs >= AHD_SCB_MAX_ALLOC)
    359  1.13   bouyer 			chan->chan_flags &= ~SCSIPI_CHAN_CANGROW;
    360   1.1     fvdl 		break;
    361   1.1     fvdl 
    362   1.1     fvdl 	case ADAPTER_REQ_SET_XFER_MODE:
    363   1.1     fvdl 	    {
    364   1.1     fvdl 		struct scsipi_xfer_mode *xm = arg;
    365   1.1     fvdl 		struct ahd_devinfo devinfo;
    366   1.1     fvdl 		int target_id, our_id, first;
    367   1.1     fvdl 		u_int width;
    368   1.1     fvdl 		int s;
    369   1.1     fvdl 		char channel;
    370   1.6     fvdl 		u_int ppr_options, period, offset;
    371   1.6     fvdl 		uint16_t old_autoneg;
    372   1.1     fvdl 
    373  1.12    perry 		target_id = xm->xm_target;
    374   1.1     fvdl 		our_id = chan->chan_id;
    375   1.1     fvdl 		channel = 'A';
    376   1.1     fvdl 		s = splbio();
    377   1.1     fvdl 		tinfo = ahd_fetch_transinfo(ahd, channel, our_id, target_id,
    378   1.1     fvdl 		    &tstate);
    379   1.1     fvdl 		ahd_compile_devinfo(&devinfo, our_id, target_id,
    380   1.1     fvdl 		    0, channel, ROLE_INITIATOR);
    381   1.1     fvdl 
    382   1.6     fvdl 		old_autoneg = tstate->auto_negotiate;
    383   1.6     fvdl 
    384   1.1     fvdl 		/*
    385   1.1     fvdl 		 * XXX since the period and offset are not provided here,
    386   1.1     fvdl 		 * fake things by forcing a renegotiation using the user
    387   1.1     fvdl 		 * settings if this is called for the first time (i.e.
    388   1.1     fvdl 		 * during probe). Also, cap various values at the user
    389   1.1     fvdl 		 * values, assuming that the user set it up that way.
    390   1.1     fvdl 		 */
    391   1.1     fvdl 		if (ahd->inited_target[target_id] == 0) {
    392   1.6     fvdl 			period = tinfo->user.period;
    393   1.6     fvdl 			offset = tinfo->user.offset;
    394   1.6     fvdl 			ppr_options = tinfo->user.ppr_options;
    395   1.6     fvdl 			width = tinfo->user.width;
    396   1.1     fvdl 			tstate->tagenable |=
    397   1.1     fvdl 			    (ahd->user_tagenable & devinfo.target_mask);
    398   1.1     fvdl 			tstate->discenable |=
    399   1.1     fvdl 			    (ahd->user_discenable & devinfo.target_mask);
    400   1.1     fvdl 			ahd->inited_target[target_id] = 1;
    401   1.1     fvdl 			first = 1;
    402   1.1     fvdl 		} else
    403   1.1     fvdl 			first = 0;
    404   1.1     fvdl 
    405   1.2     fvdl 		if (xm->xm_mode & (PERIPH_CAP_WIDE16 | PERIPH_CAP_DT))
    406   1.1     fvdl 			width = MSG_EXT_WDTR_BUS_16_BIT;
    407   1.1     fvdl 		else
    408   1.1     fvdl 			width = MSG_EXT_WDTR_BUS_8_BIT;
    409   1.1     fvdl 
    410   1.1     fvdl 		ahd_validate_width(ahd, NULL, &width, ROLE_UNKNOWN);
    411   1.1     fvdl 		if (width > tinfo->user.width)
    412   1.1     fvdl 			width = tinfo->user.width;
    413   1.6     fvdl 		ahd_set_width(ahd, &devinfo, width, AHD_TRANS_GOAL, FALSE);
    414   1.1     fvdl 
    415   1.2     fvdl 		if (!(xm->xm_mode & (PERIPH_CAP_SYNC | PERIPH_CAP_DT))) {
    416   1.6     fvdl 			period = 0;
    417   1.6     fvdl 			offset = 0;
    418   1.6     fvdl 			ppr_options = 0;
    419   1.1     fvdl 		}
    420   1.1     fvdl 
    421   1.1     fvdl 		if ((xm->xm_mode & PERIPH_CAP_DT) &&
    422   1.1     fvdl 		    (tinfo->user.ppr_options & MSG_EXT_PPR_DT_REQ))
    423   1.6     fvdl 			ppr_options |= MSG_EXT_PPR_DT_REQ;
    424   1.1     fvdl 		else
    425   1.6     fvdl 			ppr_options &= ~MSG_EXT_PPR_DT_REQ;
    426   1.6     fvdl 
    427   1.6     fvdl 		if ((tstate->discenable & devinfo.target_mask) == 0 ||
    428   1.6     fvdl 		    (tstate->tagenable & devinfo.target_mask) == 0)
    429   1.6     fvdl 			ppr_options &= ~MSG_EXT_PPR_IU_REQ;
    430   1.1     fvdl 
    431   1.1     fvdl 		if ((xm->xm_mode & PERIPH_CAP_TQING) &&
    432   1.1     fvdl 		    (ahd->user_tagenable & devinfo.target_mask))
    433   1.1     fvdl 			tstate->tagenable |= devinfo.target_mask;
    434   1.1     fvdl 		else
    435   1.1     fvdl 			tstate->tagenable &= ~devinfo.target_mask;
    436   1.1     fvdl 
    437   1.6     fvdl 		ahd_find_syncrate(ahd, &period, &ppr_options, AHD_SYNCRATE_MAX);
    438   1.6     fvdl 		ahd_validate_offset(ahd, NULL, period, &offset,
    439   1.6     fvdl 		    MSG_EXT_WDTR_BUS_8_BIT, ROLE_UNKNOWN);
    440   1.6     fvdl 		if (offset == 0) {
    441   1.6     fvdl 			period = 0;
    442   1.6     fvdl 			ppr_options = 0;
    443   1.6     fvdl 		}
    444   1.6     fvdl 		if (ppr_options != 0
    445   1.6     fvdl 		    && tinfo->user.transport_version >= 3) {
    446   1.6     fvdl 			tinfo->goal.transport_version =
    447   1.6     fvdl 			    tinfo->user.transport_version;
    448   1.6     fvdl 			tinfo->curr.transport_version =
    449   1.6     fvdl 			    tinfo->user.transport_version;
    450   1.6     fvdl 		}
    451   1.6     fvdl 
    452   1.6     fvdl 		ahd_set_syncrate(ahd, &devinfo, period, offset,
    453   1.6     fvdl 		    ppr_options, AHD_TRANS_GOAL, FALSE);
    454   1.6     fvdl 
    455   1.1     fvdl 		/*
    456   1.1     fvdl 		 * If this is the first request, and no negotiation is
    457   1.1     fvdl 		 * needed, just confirm the state to the scsipi layer,
    458   1.1     fvdl 		 * so that it can print a message.
    459   1.1     fvdl 		 */
    460   1.6     fvdl 		if (old_autoneg == tstate->auto_negotiate && first) {
    461   1.6     fvdl 			xm->xm_mode = 0;
    462   1.6     fvdl 			xm->xm_period = tinfo->curr.period;
    463   1.6     fvdl 			xm->xm_offset = tinfo->curr.offset;
    464   1.6     fvdl 			if (tinfo->curr.width == MSG_EXT_WDTR_BUS_16_BIT)
    465   1.6     fvdl 				xm->xm_mode |= PERIPH_CAP_WIDE16;
    466   1.6     fvdl 			if (tinfo->curr.period)
    467   1.6     fvdl 				xm->xm_mode |= PERIPH_CAP_SYNC;
    468   1.6     fvdl 			if (tstate->tagenable & devinfo.target_mask)
    469   1.6     fvdl 				xm->xm_mode |= PERIPH_CAP_TQING;
    470   1.6     fvdl 			if (tinfo->curr.ppr_options & MSG_EXT_PPR_DT_REQ)
    471   1.6     fvdl 				xm->xm_mode |= PERIPH_CAP_DT;
    472   1.1     fvdl 			scsipi_async_event(chan, ASYNC_EVENT_XFER_MODE, xm);
    473   1.6     fvdl 		}
    474   1.1     fvdl 		splx(s);
    475   1.1     fvdl 	    }
    476   1.1     fvdl 	}
    477  1.12    perry 
    478   1.1     fvdl 	return;
    479   1.1     fvdl }
    480   1.1     fvdl 
    481   1.1     fvdl static void
    482   1.1     fvdl ahd_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments)
    483   1.1     fvdl {
    484   1.1     fvdl 	struct scb *scb;
    485   1.1     fvdl 	struct scsipi_xfer *xs;
    486   1.1     fvdl         struct ahd_softc *ahd;
    487   1.1     fvdl 	struct ahd_initiator_tinfo *tinfo;
    488   1.1     fvdl 	struct ahd_tmode_tstate *tstate;
    489   1.1     fvdl 	u_int  mask;
    490   1.1     fvdl         int    s;
    491   1.1     fvdl 
    492   1.1     fvdl 	scb = (struct scb*)arg;
    493   1.1     fvdl 	xs = scb->xs;
    494   1.1     fvdl 	xs->error = 0;
    495   1.1     fvdl 	xs->status = 0;
    496   1.1     fvdl 	xs->xs_status = 0;
    497   1.1     fvdl 	ahd = (void*)xs->xs_periph->periph_channel->chan_adapter->adapt_dev;
    498   1.1     fvdl 
    499   1.1     fvdl 	scb->sg_count = 0;
    500   1.1     fvdl 	if (nsegments != 0) {
    501   1.1     fvdl 		void *sg;
    502   1.1     fvdl 		int op;
    503   1.1     fvdl 		u_int i;
    504   1.1     fvdl 
    505   1.1     fvdl 		ahd_setup_data_scb(ahd, scb);
    506   1.1     fvdl 
    507   1.1     fvdl 		/* Copy the segments into our SG list */
    508   1.1     fvdl 		for (i = nsegments, sg = scb->sg_list; i > 0; i--) {
    509   1.1     fvdl 
    510   1.1     fvdl 			sg = ahd_sg_setup(ahd, scb, sg, dm_segs->ds_addr,
    511   1.1     fvdl 					  dm_segs->ds_len,
    512   1.1     fvdl 					  /*last*/i == 1);
    513   1.1     fvdl 			dm_segs++;
    514   1.1     fvdl 		}
    515  1.12    perry 
    516   1.1     fvdl 		if (xs->xs_control & XS_CTL_DATA_IN)
    517   1.1     fvdl 			op = BUS_DMASYNC_PREREAD;
    518   1.1     fvdl 		else
    519   1.1     fvdl 			op = BUS_DMASYNC_PREWRITE;
    520   1.1     fvdl 
    521  1.12    perry 		bus_dmamap_sync(ahd->parent_dmat, scb->dmamap, 0,
    522   1.1     fvdl 				scb->dmamap->dm_mapsize, op);
    523   1.1     fvdl 	}
    524   1.1     fvdl 
    525   1.1     fvdl 	ahd_lock(ahd, &s);
    526   1.1     fvdl 
    527   1.1     fvdl 	/*
    528   1.1     fvdl 	 * Last time we need to check if this SCB needs to
    529   1.1     fvdl 	 * be aborted.
    530   1.1     fvdl 	 */
    531   1.1     fvdl 	if (ahd_get_scsi_status(scb) == XS_STS_DONE) {
    532   1.1     fvdl 		if (nsegments != 0)
    533   1.1     fvdl 			bus_dmamap_unload(ahd->parent_dmat,
    534   1.1     fvdl 					  scb->dmamap);
    535   1.1     fvdl 		ahd_free_scb(ahd, scb);
    536   1.1     fvdl 		ahd_unlock(ahd, &s);
    537   1.1     fvdl 		return;
    538   1.1     fvdl 	}
    539   1.1     fvdl 
    540   1.1     fvdl 	tinfo = ahd_fetch_transinfo(ahd, SCSIID_CHANNEL(ahd, scb->hscb->scsiid),
    541   1.1     fvdl 				    SCSIID_OUR_ID(scb->hscb->scsiid),
    542   1.1     fvdl 				    SCSIID_TARGET(ahd, scb->hscb->scsiid),
    543   1.1     fvdl 				    &tstate);
    544   1.1     fvdl 
    545   1.1     fvdl 	mask = SCB_GET_TARGET_MASK(ahd, scb);
    546   1.1     fvdl 
    547   1.1     fvdl 	if ((tstate->discenable & mask) != 0)
    548   1.1     fvdl 		scb->hscb->control |= DISCENB;
    549   1.1     fvdl 
    550   1.1     fvdl 	if ((tstate->tagenable & mask) != 0)
    551   1.1     fvdl 		scb->hscb->control |= xs->xs_tag_type|TAG_ENB;
    552   1.1     fvdl 
    553   1.1     fvdl 	if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU) != 0) {
    554   1.1     fvdl 		scb->flags |= SCB_PACKETIZED;
    555   1.1     fvdl 		if (scb->hscb->task_management != 0)
    556   1.1     fvdl 			scb->hscb->control &= ~MK_MESSAGE;
    557   1.1     fvdl 	}
    558   1.1     fvdl 
    559   1.6     fvdl #if 0	/* This looks like it makes sense at first, but it can loop */
    560   1.1     fvdl 	if ((xs->xs_control & XS_CTL_DISCOVERY) &&
    561   1.1     fvdl 	    (tinfo->goal.width != 0
    562   1.1     fvdl 	     || tinfo->goal.period != 0
    563   1.1     fvdl 	     || tinfo->goal.ppr_options != 0)) {
    564   1.1     fvdl 		scb->flags |= SCB_NEGOTIATE;
    565   1.1     fvdl 		scb->hscb->control |= MK_MESSAGE;
    566   1.6     fvdl 	} else
    567   1.6     fvdl #endif
    568   1.6     fvdl 	if ((tstate->auto_negotiate & mask) != 0) {
    569   1.1     fvdl 	  	scb->flags |= SCB_AUTO_NEGOTIATE;
    570   1.1     fvdl 		scb->hscb->control |= MK_MESSAGE;
    571   1.1     fvdl 	}
    572   1.1     fvdl 
    573   1.1     fvdl 	LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links);
    574   1.1     fvdl 
    575   1.1     fvdl 	scb->flags |= SCB_ACTIVE;
    576   1.1     fvdl 
    577   1.1     fvdl 	if (!(xs->xs_control & XS_CTL_POLL)) {
    578   1.1     fvdl 		callout_reset(&scb->xs->xs_callout, xs->timeout > 1000000 ?
    579   1.1     fvdl 			      (xs->timeout / 1000) * hz : (xs->timeout * hz) / 1000,
    580   1.1     fvdl 			      ahd_timeout, scb);
    581   1.1     fvdl 	}
    582   1.1     fvdl 
    583   1.1     fvdl 	if ((scb->flags & SCB_TARGET_IMMEDIATE) != 0) {
    584   1.1     fvdl 		/* Define a mapping from our tag to the SCB. */
    585   1.1     fvdl 		ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb;
    586   1.1     fvdl 		ahd_pause(ahd);
    587   1.1     fvdl 		ahd_set_scbptr(ahd, SCB_GET_TAG(scb));
    588   1.1     fvdl 		ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_TARG);
    589   1.1     fvdl 		ahd_unpause(ahd);
    590   1.1     fvdl 	} else {
    591   1.1     fvdl 		ahd_queue_scb(ahd, scb);
    592   1.1     fvdl 	}
    593   1.1     fvdl 
    594   1.1     fvdl 	if (!(xs->xs_control & XS_CTL_POLL)) {
    595   1.1     fvdl                 ahd_unlock(ahd, &s);
    596   1.1     fvdl                 return;
    597   1.1     fvdl         }
    598   1.1     fvdl         /*
    599   1.1     fvdl          * If we can't use interrupts, poll for completion
    600   1.1     fvdl          */
    601   1.1     fvdl         SC_DEBUG(xs->xs_periph, SCSIPI_DB3, ("cmd_poll\n"));
    602   1.1     fvdl         do {
    603   1.1     fvdl                 if (ahd_poll(ahd, xs->timeout)) {
    604   1.1     fvdl                         if (!(xs->xs_control & XS_CTL_SILENT))
    605   1.1     fvdl                                 printf("cmd fail\n");
    606   1.1     fvdl                         ahd_timeout(scb);
    607   1.1     fvdl                         break;
    608   1.1     fvdl                 }
    609   1.1     fvdl         } while (!(xs->xs_status & XS_STS_DONE));
    610   1.1     fvdl 
    611   1.1     fvdl 	ahd_unlock(ahd, &s);
    612   1.1     fvdl }
    613   1.1     fvdl 
    614   1.1     fvdl static int
    615   1.1     fvdl ahd_poll(struct ahd_softc *ahd, int wait)
    616   1.1     fvdl {
    617   1.1     fvdl 
    618   1.1     fvdl 	while (--wait) {
    619   1.1     fvdl                 DELAY(1000);
    620   1.1     fvdl                 if (ahd_inb(ahd, INTSTAT) & INT_PEND)
    621   1.1     fvdl                         break;
    622   1.1     fvdl         }
    623   1.1     fvdl 
    624   1.1     fvdl         if (wait == 0) {
    625   1.1     fvdl                 printf("%s: board is not responding\n", ahd_name(ahd));
    626   1.1     fvdl                 return (EIO);
    627   1.1     fvdl         }
    628   1.1     fvdl 
    629   1.1     fvdl         ahd_intr((void *)ahd);
    630   1.1     fvdl         return (0);
    631   1.1     fvdl }
    632   1.1     fvdl 
    633   1.1     fvdl 
    634   1.1     fvdl static void
    635   1.1     fvdl ahd_setup_data(struct ahd_softc *ahd, struct scsipi_xfer *xs,
    636   1.1     fvdl 	       struct scb *scb)
    637   1.1     fvdl {
    638   1.1     fvdl 	struct hardware_scb *hscb;
    639   1.1     fvdl 
    640   1.1     fvdl 	hscb = scb->hscb;
    641   1.1     fvdl 	xs->resid = xs->status = 0;
    642   1.1     fvdl 
    643   1.1     fvdl 	hscb->cdb_len = xs->cmdlen;
    644   1.1     fvdl 	if (hscb->cdb_len > MAX_CDB_LEN) {
    645   1.1     fvdl 		int s;
    646   1.1     fvdl 		/*
    647   1.1     fvdl 		 * Should CAM start to support CDB sizes
    648   1.1     fvdl 		 * greater than 16 bytes, we could use
    649   1.1     fvdl 		 * the sense buffer to store the CDB.
    650   1.1     fvdl 		 */
    651  1.12    perry 		ahd_set_transaction_status(scb,
    652   1.1     fvdl 					   XS_DRIVER_STUFFUP);
    653   1.1     fvdl 
    654   1.1     fvdl 		ahd_lock(ahd, &s);
    655   1.1     fvdl 		ahd_free_scb(ahd, scb);
    656   1.1     fvdl 		ahd_unlock(ahd, &s);
    657   1.1     fvdl 		scsipi_done(xs);
    658   1.1     fvdl 	}
    659   1.1     fvdl 	memcpy(hscb->shared_data.idata.cdb, xs->cmd, hscb->cdb_len);
    660  1.12    perry 
    661   1.1     fvdl 	/* Only use S/G if there is a transfer */
    662   1.1     fvdl         if (xs->datalen) {
    663   1.1     fvdl                 int error;
    664   1.1     fvdl 
    665   1.1     fvdl                 error = bus_dmamap_load(ahd->parent_dmat,
    666   1.1     fvdl 					scb->dmamap, xs->data,
    667   1.1     fvdl 					xs->datalen, NULL,
    668   1.1     fvdl 					((xs->xs_control & XS_CTL_NOSLEEP) ?
    669   1.1     fvdl 					 BUS_DMA_NOWAIT : BUS_DMA_WAITOK) |
    670   1.1     fvdl 					BUS_DMA_STREAMING |
    671   1.1     fvdl 					((xs->xs_control & XS_CTL_DATA_IN) ?
    672   1.1     fvdl 					 BUS_DMA_READ : BUS_DMA_WRITE));
    673   1.1     fvdl                 if (error) {
    674   1.1     fvdl #ifdef AHD_DEBUG
    675   1.1     fvdl                         printf("%s: in ahc_setup_data(): bus_dmamap_load() "
    676   1.1     fvdl 			       "= %d\n",
    677   1.1     fvdl 			       ahd_name(ahd), error);
    678   1.1     fvdl #endif
    679   1.1     fvdl                         xs->error = XS_RESOURCE_SHORTAGE;
    680   1.1     fvdl                         scsipi_done(xs);
    681   1.1     fvdl                         return;
    682   1.1     fvdl                 }
    683   1.1     fvdl                 ahd_execute_scb(scb,
    684   1.1     fvdl 				scb->dmamap->dm_segs,
    685   1.1     fvdl 				scb->dmamap->dm_nsegs);
    686   1.1     fvdl         } else {
    687   1.1     fvdl                 ahd_execute_scb(scb, NULL, 0);
    688   1.1     fvdl         }
    689   1.1     fvdl }
    690   1.1     fvdl 
    691   1.1     fvdl void
    692   1.1     fvdl ahd_timeout(void *arg)
    693   1.1     fvdl {
    694   1.1     fvdl 	struct	scb	  *scb;
    695   1.1     fvdl 	struct	ahd_softc *ahd;
    696   1.1     fvdl 	ahd_mode_state	   saved_modes;
    697   1.1     fvdl 	int		   s;
    698   1.1     fvdl 
    699  1.12    perry 	scb = (struct scb *)arg;
    700   1.1     fvdl 	ahd = (struct ahd_softc *)scb->ahd_softc;
    701   1.1     fvdl 
    702   1.1     fvdl 	printf("%s: ahd_timeout\n", ahd_name(ahd));
    703   1.1     fvdl 
    704   1.1     fvdl 	ahd_lock(ahd, &s);
    705   1.1     fvdl 
    706   1.1     fvdl 	ahd_pause_and_flushwork(ahd);
    707   1.1     fvdl 	saved_modes = ahd_save_modes(ahd);
    708   1.1     fvdl #if 0
    709   1.1     fvdl 	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
    710   1.1     fvdl 	ahd_outb(ahd, SCSISIGO, ACKO);
    711   1.1     fvdl 	printf("set ACK\n");
    712   1.1     fvdl 	ahd_outb(ahd, SCSISIGO, 0);
    713   1.1     fvdl 	printf("clearing Ack\n");
    714   1.1     fvdl 	ahd_restore_modes(ahd, saved_modes);
    715   1.1     fvdl #endif
    716   1.1     fvdl 	if ((scb->flags & SCB_ACTIVE) == 0) {
    717   1.1     fvdl 		/* Previous timeout took care of me already */
    718   1.1     fvdl 		printf("%s: Timedout SCB already complete. "
    719   1.1     fvdl 		       "Interrupts may not be functioning.\n", ahd_name(ahd));
    720   1.1     fvdl 		ahd_unpause(ahd);
    721   1.1     fvdl 		ahd_unlock(ahd, &s);
    722   1.1     fvdl 		return;
    723   1.1     fvdl 	}
    724   1.1     fvdl 
    725   1.1     fvdl 	ahd_print_path(ahd, scb);
    726   1.1     fvdl 	printf("SCB 0x%x - timed out\n", SCB_GET_TAG(scb));
    727   1.1     fvdl 	ahd_dump_card_state(ahd);
    728   1.1     fvdl 	ahd_reset_channel(ahd, SIM_CHANNEL(ahd, sim),
    729   1.1     fvdl 			  /*initiate reset*/TRUE);
    730   1.1     fvdl 	ahd_unlock(ahd, &s);
    731   1.1     fvdl 	return;
    732   1.1     fvdl }
    733   1.1     fvdl 
    734   1.1     fvdl int
    735   1.1     fvdl ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg)
    736   1.1     fvdl {
    737   1.1     fvdl 	ahd->platform_data = malloc(sizeof(struct ahd_platform_data), M_DEVBUF,
    738   1.1     fvdl 				    M_NOWAIT /*| M_ZERO*/);
    739   1.1     fvdl 	if (ahd->platform_data == NULL)
    740   1.1     fvdl 		return (ENOMEM);
    741   1.1     fvdl 
    742   1.1     fvdl 	memset(ahd->platform_data, 0, sizeof(struct ahd_platform_data));
    743   1.1     fvdl 
    744   1.1     fvdl 	return (0);
    745   1.1     fvdl }
    746   1.1     fvdl 
    747   1.1     fvdl void
    748   1.1     fvdl ahd_platform_free(struct ahd_softc *ahd)
    749   1.1     fvdl {
    750   1.1     fvdl 	free(ahd->platform_data, M_DEVBUF);
    751   1.1     fvdl }
    752   1.1     fvdl 
    753   1.1     fvdl int
    754   1.1     fvdl ahd_softc_comp(struct ahd_softc *lahd, struct ahd_softc *rahd)
    755   1.1     fvdl {
    756   1.1     fvdl 	/* We don't sort softcs under NetBSD so report equal always */
    757   1.1     fvdl 	return (0);
    758   1.1     fvdl }
    759   1.1     fvdl 
    760   1.1     fvdl int
    761   1.1     fvdl ahd_detach(struct device *self, int flags)
    762   1.1     fvdl {
    763   1.1     fvdl 	int rv = 0;
    764   1.1     fvdl 
    765   1.1     fvdl 	struct ahd_softc *ahd = (struct ahd_softc*)self;
    766   1.1     fvdl 
    767   1.1     fvdl 	if (ahd->sc_child != NULL)
    768   1.1     fvdl 		rv = config_detach((void *)ahd->sc_child, flags);
    769   1.1     fvdl 
    770   1.1     fvdl 	shutdownhook_disestablish(ahd->shutdown_hook);
    771   1.1     fvdl 
    772   1.1     fvdl 	ahd_free(ahd);
    773   1.1     fvdl 
    774   1.1     fvdl 	return rv;
    775   1.1     fvdl }
    776   1.1     fvdl 
    777   1.1     fvdl void
    778   1.1     fvdl ahd_platform_set_tags(struct ahd_softc *ahd,
    779   1.1     fvdl 		      struct ahd_devinfo *devinfo, ahd_queue_alg alg)
    780   1.1     fvdl {
    781   1.1     fvdl         struct ahd_tmode_tstate *tstate;
    782   1.1     fvdl 
    783   1.7   simonb         ahd_fetch_transinfo(ahd, devinfo->channel, devinfo->our_scsiid,
    784   1.7   simonb                             devinfo->target, &tstate);
    785   1.1     fvdl 
    786   1.1     fvdl         if (alg != AHD_QUEUE_NONE)
    787   1.1     fvdl                 tstate->tagenable |= devinfo->target_mask;
    788   1.1     fvdl 	else
    789   1.1     fvdl 	  	tstate->tagenable &= ~devinfo->target_mask;
    790   1.1     fvdl }
    791   1.1     fvdl 
    792   1.1     fvdl void
    793   1.1     fvdl ahd_send_async(struct ahd_softc *ahc, char channel, u_int target, u_int lun,
    794   1.1     fvdl 	       ac_code code, void *opt_arg)
    795   1.1     fvdl {
    796   1.1     fvdl 	struct ahd_tmode_tstate *tstate;
    797   1.1     fvdl 	struct ahd_initiator_tinfo *tinfo;
    798   1.1     fvdl 	struct ahd_devinfo devinfo;
    799   1.1     fvdl 	struct scsipi_channel *chan;
    800   1.1     fvdl 	struct scsipi_xfer_mode xm;
    801   1.1     fvdl 
    802   1.1     fvdl #ifdef DIAGNOSTIC
    803   1.1     fvdl 	if (channel != 'A')
    804   1.1     fvdl 		panic("ahd_send_async: not channel A");
    805   1.1     fvdl #endif
    806   1.1     fvdl 	chan = &ahc->sc_channel;
    807   1.1     fvdl 	switch (code) {
    808   1.1     fvdl 	case AC_TRANSFER_NEG:
    809   1.1     fvdl 		tinfo = ahd_fetch_transinfo(ahc, channel, ahc->our_id, target,
    810   1.1     fvdl 			    &tstate);
    811   1.1     fvdl 		ahd_compile_devinfo(&devinfo, ahc->our_id, target, lun,
    812   1.1     fvdl 		    channel, ROLE_UNKNOWN);
    813   1.1     fvdl 		/*
    814   1.1     fvdl 		 * Don't bother if negotiating. XXX?
    815   1.1     fvdl 		 */
    816   1.1     fvdl 		if (tinfo->curr.period != tinfo->goal.period
    817   1.1     fvdl 		    || tinfo->curr.width != tinfo->goal.width
    818   1.1     fvdl 		    || tinfo->curr.offset != tinfo->goal.offset
    819   1.1     fvdl 		    || tinfo->curr.ppr_options != tinfo->goal.ppr_options)
    820   1.1     fvdl 			break;
    821   1.1     fvdl 		xm.xm_target = target;
    822   1.1     fvdl 		xm.xm_mode = 0;
    823   1.1     fvdl 		xm.xm_period = tinfo->curr.period;
    824   1.1     fvdl 		xm.xm_offset = tinfo->curr.offset;
    825   1.1     fvdl 		if (tinfo->goal.ppr_options & MSG_EXT_PPR_DT_REQ)
    826   1.1     fvdl 			xm.xm_mode |= PERIPH_CAP_DT;
    827   1.1     fvdl 		if (tinfo->curr.width == MSG_EXT_WDTR_BUS_16_BIT)
    828   1.1     fvdl 			xm.xm_mode |= PERIPH_CAP_WIDE16;
    829   1.1     fvdl 		if (tinfo->curr.period)
    830   1.1     fvdl 			xm.xm_mode |= PERIPH_CAP_SYNC;
    831   1.1     fvdl 		if (tstate->tagenable & devinfo.target_mask)
    832   1.1     fvdl 			xm.xm_mode |= PERIPH_CAP_TQING;
    833   1.1     fvdl 		scsipi_async_event(chan, ASYNC_EVENT_XFER_MODE, &xm);
    834   1.1     fvdl 		break;
    835   1.1     fvdl 	case AC_BUS_RESET:
    836   1.1     fvdl 		scsipi_async_event(chan, ASYNC_EVENT_RESET, NULL);
    837   1.1     fvdl 	case AC_SENT_BDR:
    838   1.1     fvdl 	default:
    839   1.1     fvdl 		break;
    840   1.1     fvdl 	}
    841   1.1     fvdl }
    842