Home | History | Annotate | Line # | Download | only in ic
aic79xx_osm.c revision 1.4
      1  1.4  lukem /*	$NetBSD: aic79xx_osm.c,v 1.4 2003/07/14 15:47:06 lukem 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.1   fvdl  * $FreeBSD: src/sys/dev/aic7xxx/aic79xx_osm.c,v 1.8 2003/02/27 23:23:16 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.4  lukem __KERNEL_RCSID(0, "$NetBSD: aic79xx_osm.c,v 1.4 2003/07/14 15:47:06 lukem 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.1   fvdl 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.1   fvdl 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.1   fvdl 	ahd_controller_info(ahd, 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.1   fvdl 
     85  1.1   fvdl 	ahd->sc_adapter.adapt_openings = AHD_MAX_QUEUE;
     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.1   fvdl 
     99  1.1   fvdl 	ahd->sc_child = config_found((void *)ahd, &ahd->sc_channel, scsiprint);
    100  1.1   fvdl 
    101  1.1   fvdl 	ahd_intr_enable(ahd, TRUE);
    102  1.1   fvdl 
    103  1.3   fvdl 	if (ahd->flags & AHD_RESET_BUS_A)
    104  1.3   fvdl 		ahd_reset_channel(ahd, 'A', TRUE);
    105  1.3   fvdl 
    106  1.1   fvdl         ahd_unlock(ahd, &s);
    107  1.1   fvdl 
    108  1.1   fvdl 	return (1);
    109  1.1   fvdl }
    110  1.1   fvdl 
    111  1.1   fvdl static int
    112  1.1   fvdl ahd_ioctl(struct scsipi_channel *channel, u_long cmd,
    113  1.1   fvdl 	  caddr_t addr, int flag, struct proc *p)
    114  1.1   fvdl {
    115  1.1   fvdl         struct ahd_softc *ahd = (void *)channel->chan_adapter->adapt_dev;
    116  1.1   fvdl         int s, ret = ENOTTY;
    117  1.1   fvdl 
    118  1.1   fvdl         switch (cmd) {
    119  1.1   fvdl         case SCBUSIORESET:
    120  1.1   fvdl                 s = splbio();
    121  1.1   fvdl                 ahd_reset_channel(ahd, channel->chan_channel == 1 ? 'B' : 'A', TRUE);
    122  1.1   fvdl                 splx(s);
    123  1.1   fvdl                 ret = 0;
    124  1.1   fvdl                 break;
    125  1.1   fvdl         default:
    126  1.1   fvdl                 break;
    127  1.1   fvdl         }
    128  1.1   fvdl 
    129  1.1   fvdl         return ret;
    130  1.1   fvdl }
    131  1.1   fvdl 
    132  1.1   fvdl /*
    133  1.1   fvdl  * Catch an interrupt from the adapter
    134  1.1   fvdl  */
    135  1.1   fvdl void
    136  1.1   fvdl ahd_platform_intr(void *arg)
    137  1.1   fvdl {
    138  1.1   fvdl 	struct	ahd_softc *ahd;
    139  1.1   fvdl 
    140  1.1   fvdl 	ahd = (struct ahd_softc *)arg;
    141  1.1   fvdl 
    142  1.1   fvdl 	printf("%s; ahd_platform_intr\n", ahd_name(ahd));
    143  1.1   fvdl 
    144  1.1   fvdl 	ahd_intr(ahd);
    145  1.1   fvdl }
    146  1.1   fvdl 
    147  1.1   fvdl /*
    148  1.1   fvdl  * We have an scb which has been processed by the
    149  1.1   fvdl  * adaptor, now we look to see how the operation * went.
    150  1.1   fvdl  */
    151  1.1   fvdl void
    152  1.1   fvdl ahd_done(struct ahd_softc *ahd, struct scb *scb)
    153  1.1   fvdl {
    154  1.1   fvdl 	struct scsipi_xfer	*xs;
    155  1.1   fvdl 	struct scsipi_periph	*periph;
    156  1.1   fvdl 	int			target;
    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 	target = periph->periph_target;
    167  1.1   fvdl 
    168  1.1   fvdl 	if (xs->datalen) {
    169  1.1   fvdl 		int op;
    170  1.1   fvdl 
    171  1.1   fvdl 		if (xs->xs_control & XS_CTL_DATA_IN)
    172  1.1   fvdl 		  op = BUS_DMASYNC_POSTREAD;
    173  1.1   fvdl 		else
    174  1.1   fvdl 		  op = BUS_DMASYNC_POSTWRITE;
    175  1.1   fvdl 
    176  1.1   fvdl 		bus_dmamap_sync(ahd->parent_dmat, scb->dmamap, 0,
    177  1.1   fvdl 				scb->dmamap->dm_mapsize, op);
    178  1.1   fvdl                 bus_dmamap_unload(ahd->parent_dmat, scb->dmamap);
    179  1.1   fvdl         }
    180  1.1   fvdl 
    181  1.1   fvdl 	/*
    182  1.1   fvdl 	 * If the recovery SCB completes, we have to be
    183  1.1   fvdl 	 * out of our timeout.
    184  1.1   fvdl 	 */
    185  1.1   fvdl 	if ((scb->flags & SCB_RECOVERY_SCB) != 0) {
    186  1.1   fvdl 		struct	scb *list_scb;
    187  1.1   fvdl 
    188  1.1   fvdl 		/*
    189  1.1   fvdl 		 * We were able to complete the command successfully,
    190  1.1   fvdl 		 * so reinstate the timeouts for all other pending
    191  1.1   fvdl 		 * commands.
    192  1.1   fvdl 		 */
    193  1.1   fvdl 		LIST_FOREACH(list_scb, &ahd->pending_scbs, pending_links) {
    194  1.1   fvdl 			struct scsipi_xfer	*txs = list_scb->xs;
    195  1.1   fvdl 
    196  1.1   fvdl 			if (!(txs->xs_control & XS_CTL_POLL)) {
    197  1.1   fvdl                                 callout_reset(&txs->xs_callout,
    198  1.1   fvdl                                     (txs->timeout > 1000000) ?
    199  1.1   fvdl                                     (txs->timeout / 1000) * hz :
    200  1.1   fvdl                                     (txs->timeout * hz) / 1000,
    201  1.1   fvdl                                     ahd_timeout, list_scb);
    202  1.1   fvdl                         }
    203  1.1   fvdl 		}
    204  1.1   fvdl 
    205  1.1   fvdl 		if (ahd_get_transaction_status(scb) != XS_NOERROR)
    206  1.1   fvdl 		  ahd_set_transaction_status(scb, XS_TIMEOUT);
    207  1.1   fvdl                 scsipi_printaddr(xs->xs_periph);
    208  1.1   fvdl 		printf("%s: no longer in timeout, status = %x\n",
    209  1.1   fvdl 		       ahd_name(ahd), xs->status);
    210  1.1   fvdl 	}
    211  1.1   fvdl 
    212  1.1   fvdl 	if (xs->error != XS_NOERROR) {
    213  1.1   fvdl                 /* Don't clobber any existing error state */
    214  1.1   fvdl 	} else if ((xs->status == SCSI_STATUS_BUSY) ||
    215  1.1   fvdl 		   (xs->status == SCSI_STATUS_QUEUE_FULL)) {
    216  1.1   fvdl 	  	ahd_set_transaction_status(scb, XS_BUSY);
    217  1.1   fvdl 		printf("%s: drive (ID %d, LUN %d) queue full (SCB 0x%x)\n",
    218  1.1   fvdl 		       ahd_name(ahd), SCB_GET_TARGET(ahd,scb), SCB_GET_LUN(scb), SCB_GET_TAG(scb));
    219  1.1   fvdl         } else if ((scb->flags & SCB_SENSE) != 0) {
    220  1.1   fvdl                 /*
    221  1.1   fvdl                  * We performed autosense retrieval.
    222  1.1   fvdl                  *
    223  1.1   fvdl                  * zero the sense data before having
    224  1.1   fvdl                  * the drive fill it.  The SCSI spec mandates
    225  1.1   fvdl                  * that any untransferred data should be
    226  1.1   fvdl                  * assumed to be zero.  Complete the 'bounce'
    227  1.1   fvdl                  * of sense information through buffers accessible
    228  1.1   fvdl                  * via bus-space by copying it into the clients
    229  1.1   fvdl                  * csio.
    230  1.1   fvdl                  */
    231  1.1   fvdl                 memset(&xs->sense.scsi_sense, 0, sizeof(xs->sense.scsi_sense));
    232  1.1   fvdl                 memcpy(&xs->sense.scsi_sense, ahd_get_sense_buf(ahd, scb),
    233  1.1   fvdl 		       sizeof(struct scsipi_sense_data));
    234  1.1   fvdl 
    235  1.1   fvdl                 ahd_set_transaction_status(scb, XS_SENSE);
    236  1.1   fvdl         } else if ((scb->flags & SCB_PKT_SENSE) != 0) {
    237  1.1   fvdl 		struct scsi_status_iu_header *siu;
    238  1.1   fvdl 		u_int sense_len;
    239  1.1   fvdl 		int i;
    240  1.1   fvdl 
    241  1.1   fvdl 		/*
    242  1.1   fvdl 		 * Copy only the sense data into the provided buffer.
    243  1.1   fvdl 		 */
    244  1.1   fvdl 		siu = (struct scsi_status_iu_header *)scb->sense_data;
    245  1.1   fvdl 		sense_len = MIN(scsi_4btoul(siu->sense_length),
    246  1.1   fvdl 				sizeof(&xs->sense.scsi_sense));
    247  1.1   fvdl 		memset(&xs->sense.scsi_sense, 0, sizeof(xs->sense.scsi_sense));
    248  1.1   fvdl 		memcpy(&xs->sense.scsi_sense,
    249  1.1   fvdl 		       scb->sense_data + SIU_SENSE_OFFSET(siu), sense_len);
    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.1   fvdl 
    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.1   fvdl         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.1   fvdl                 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.1   fvdl 		col_idx = AHD_NEVER_COL_IDX; /* ??? */
    314  1.1   fvdl 
    315  1.1   fvdl 		if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) {
    316  1.1   fvdl 			xs->error = XS_RESOURCE_SHORTAGE;
    317  1.1   fvdl 			ahd_unlock(ahd, &s);
    318  1.1   fvdl 			scsipi_done(xs);
    319  1.1   fvdl 			return;
    320  1.1   fvdl 		}
    321  1.1   fvdl 		ahd_unlock(ahd, &s);
    322  1.1   fvdl 
    323  1.1   fvdl 		hscb = scb->hscb;
    324  1.1   fvdl 
    325  1.1   fvdl 		SC_DEBUG(periph, SCSIPI_DB3, ("start scb(%p)\n", scb));
    326  1.1   fvdl 		scb->xs = xs;
    327  1.1   fvdl 
    328  1.1   fvdl 		/*
    329  1.1   fvdl 		 * Put all the arguments for the xfer in the scb
    330  1.1   fvdl 		 */
    331  1.1   fvdl 		hscb->control = 0;
    332  1.1   fvdl 		hscb->scsiid = BUILD_SCSIID(ahd, sim, target_id, our_id);
    333  1.1   fvdl 		hscb->lun = periph->periph_lun;
    334  1.1   fvdl 		if (xs->xs_control & XS_CTL_RESET) {
    335  1.1   fvdl 			hscb->cdb_len = 0;
    336  1.1   fvdl 			scb->flags |= SCB_DEVICE_RESET;
    337  1.1   fvdl 			hscb->control |= MK_MESSAGE;
    338  1.1   fvdl 			hscb->task_management = SIU_TASKMGMT_LUN_RESET;
    339  1.1   fvdl 			ahd_execute_scb(scb, NULL, 0);
    340  1.1   fvdl 		} else {
    341  1.1   fvdl 			hscb->task_management = 0;
    342  1.1   fvdl 		}
    343  1.1   fvdl 
    344  1.1   fvdl 		ahd_setup_data(ahd, xs, scb);
    345  1.1   fvdl 		break;
    346  1.1   fvdl 	  }
    347  1.1   fvdl 
    348  1.1   fvdl 	case ADAPTER_REQ_GROW_RESOURCES:
    349  1.1   fvdl 		printf("%s: ADAPTER_REQ_GROW_RESOURCES\n", ahd_name(ahd));
    350  1.1   fvdl 		break;
    351  1.1   fvdl 
    352  1.1   fvdl 	case ADAPTER_REQ_SET_XFER_MODE:
    353  1.1   fvdl 	    {
    354  1.1   fvdl 		struct scsipi_xfer_mode *xm = arg;
    355  1.1   fvdl 		struct ahd_devinfo devinfo;
    356  1.1   fvdl 		int target_id, our_id, first;
    357  1.1   fvdl 		u_int width;
    358  1.1   fvdl 		int s;
    359  1.1   fvdl 		char channel;
    360  1.1   fvdl 
    361  1.1   fvdl 		target_id = xm->xm_target;
    362  1.1   fvdl 		our_id = chan->chan_id;
    363  1.1   fvdl 		channel = 'A';
    364  1.1   fvdl 		s = splbio();
    365  1.1   fvdl 		tinfo = ahd_fetch_transinfo(ahd, channel, our_id, target_id,
    366  1.1   fvdl 		    &tstate);
    367  1.1   fvdl 		ahd_compile_devinfo(&devinfo, our_id, target_id,
    368  1.1   fvdl 		    0, channel, ROLE_INITIATOR);
    369  1.1   fvdl 
    370  1.1   fvdl 		/*
    371  1.1   fvdl 		 * XXX since the period and offset are not provided here,
    372  1.1   fvdl 		 * fake things by forcing a renegotiation using the user
    373  1.1   fvdl 		 * settings if this is called for the first time (i.e.
    374  1.1   fvdl 		 * during probe). Also, cap various values at the user
    375  1.1   fvdl 		 * values, assuming that the user set it up that way.
    376  1.1   fvdl 		 */
    377  1.1   fvdl 		if (ahd->inited_target[target_id] == 0) {
    378  1.1   fvdl 			tinfo->goal = tinfo->user;
    379  1.1   fvdl 			tstate->tagenable |=
    380  1.1   fvdl 			    (ahd->user_tagenable & devinfo.target_mask);
    381  1.1   fvdl 			tstate->discenable |=
    382  1.1   fvdl 			    (ahd->user_discenable & devinfo.target_mask);
    383  1.1   fvdl 			ahd->inited_target[target_id] = 1;
    384  1.1   fvdl 			first = 1;
    385  1.1   fvdl 		} else
    386  1.1   fvdl 			first = 0;
    387  1.1   fvdl 
    388  1.2   fvdl 		if (xm->xm_mode & (PERIPH_CAP_WIDE16 | PERIPH_CAP_DT))
    389  1.1   fvdl 			width = MSG_EXT_WDTR_BUS_16_BIT;
    390  1.1   fvdl 		else
    391  1.1   fvdl 			width = MSG_EXT_WDTR_BUS_8_BIT;
    392  1.1   fvdl 
    393  1.1   fvdl 		ahd_validate_width(ahd, NULL, &width, ROLE_UNKNOWN);
    394  1.1   fvdl 		if (width > tinfo->user.width)
    395  1.1   fvdl 			width = tinfo->user.width;
    396  1.1   fvdl 		tinfo->goal.width = width;
    397  1.1   fvdl 
    398  1.2   fvdl 		if (!(xm->xm_mode & (PERIPH_CAP_SYNC | PERIPH_CAP_DT))) {
    399  1.1   fvdl 			tinfo->goal.period = 0;
    400  1.1   fvdl 			tinfo->goal.offset = 0;
    401  1.1   fvdl 			tinfo->goal.ppr_options = 0;
    402  1.1   fvdl 		}
    403  1.1   fvdl 
    404  1.1   fvdl 		if ((xm->xm_mode & PERIPH_CAP_DT) &&
    405  1.1   fvdl 		    (tinfo->user.ppr_options & MSG_EXT_PPR_DT_REQ))
    406  1.1   fvdl 			tinfo->goal.ppr_options |= MSG_EXT_PPR_DT_REQ;
    407  1.1   fvdl 		else
    408  1.1   fvdl 			tinfo->goal.ppr_options &= ~MSG_EXT_PPR_DT_REQ;
    409  1.1   fvdl 
    410  1.1   fvdl 		if ((xm->xm_mode & PERIPH_CAP_TQING) &&
    411  1.1   fvdl 		    (ahd->user_tagenable & devinfo.target_mask))
    412  1.1   fvdl 			tstate->tagenable |= devinfo.target_mask;
    413  1.1   fvdl 		else
    414  1.1   fvdl 			tstate->tagenable &= ~devinfo.target_mask;
    415  1.1   fvdl 
    416  1.1   fvdl 		/*
    417  1.1   fvdl 		 * If this is the first request, and no negotiation is
    418  1.1   fvdl 		 * needed, just confirm the state to the scsipi layer,
    419  1.1   fvdl 		 * so that it can print a message.
    420  1.1   fvdl 		 */
    421  1.1   fvdl 		if (!ahd_update_neg_request(ahd, &devinfo, tstate,
    422  1.1   fvdl 		    tinfo, AHD_NEG_IF_NON_ASYNC) && first)
    423  1.1   fvdl 			scsipi_async_event(chan, ASYNC_EVENT_XFER_MODE, xm);
    424  1.1   fvdl 		splx(s);
    425  1.1   fvdl 	    }
    426  1.1   fvdl 	}
    427  1.1   fvdl 
    428  1.1   fvdl 	return;
    429  1.1   fvdl }
    430  1.1   fvdl 
    431  1.1   fvdl static void
    432  1.1   fvdl ahd_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments)
    433  1.1   fvdl {
    434  1.1   fvdl 	struct scb *scb;
    435  1.1   fvdl 	struct scsipi_xfer *xs;
    436  1.1   fvdl         struct ahd_softc *ahd;
    437  1.1   fvdl 	struct ahd_initiator_tinfo *tinfo;
    438  1.1   fvdl 	struct ahd_tmode_tstate *tstate;
    439  1.1   fvdl 	u_int  mask;
    440  1.1   fvdl         int    s;
    441  1.1   fvdl 
    442  1.1   fvdl 	scb = (struct scb*)arg;
    443  1.1   fvdl 	xs = scb->xs;
    444  1.1   fvdl 	xs->error = 0;
    445  1.1   fvdl 	xs->status = 0;
    446  1.1   fvdl 	xs->xs_status = 0;
    447  1.1   fvdl 	ahd = (void*)xs->xs_periph->periph_channel->chan_adapter->adapt_dev;
    448  1.1   fvdl 
    449  1.1   fvdl 	scb->sg_count = 0;
    450  1.1   fvdl 	if (nsegments != 0) {
    451  1.1   fvdl 		void *sg;
    452  1.1   fvdl 		int op;
    453  1.1   fvdl 		u_int i;
    454  1.1   fvdl 
    455  1.1   fvdl 		ahd_setup_data_scb(ahd, scb);
    456  1.1   fvdl 
    457  1.1   fvdl 		/* Copy the segments into our SG list */
    458  1.1   fvdl 		for (i = nsegments, sg = scb->sg_list; i > 0; i--) {
    459  1.1   fvdl 
    460  1.1   fvdl 			sg = ahd_sg_setup(ahd, scb, sg, dm_segs->ds_addr,
    461  1.1   fvdl 					  dm_segs->ds_len,
    462  1.1   fvdl 					  /*last*/i == 1);
    463  1.1   fvdl 			dm_segs++;
    464  1.1   fvdl 		}
    465  1.1   fvdl 
    466  1.1   fvdl 		if (xs->xs_control & XS_CTL_DATA_IN)
    467  1.1   fvdl 			op = BUS_DMASYNC_PREREAD;
    468  1.1   fvdl 		else
    469  1.1   fvdl 			op = BUS_DMASYNC_PREWRITE;
    470  1.1   fvdl 
    471  1.1   fvdl 		bus_dmamap_sync(ahd->parent_dmat, scb->dmamap, 0,
    472  1.1   fvdl 				scb->dmamap->dm_mapsize, op);
    473  1.1   fvdl 	}
    474  1.1   fvdl 
    475  1.1   fvdl 	ahd_lock(ahd, &s);
    476  1.1   fvdl 
    477  1.1   fvdl 	/*
    478  1.1   fvdl 	 * Last time we need to check if this SCB needs to
    479  1.1   fvdl 	 * be aborted.
    480  1.1   fvdl 	 */
    481  1.1   fvdl 	if (ahd_get_scsi_status(scb) == XS_STS_DONE) {
    482  1.1   fvdl 		if (nsegments != 0)
    483  1.1   fvdl 			bus_dmamap_unload(ahd->parent_dmat,
    484  1.1   fvdl 					  scb->dmamap);
    485  1.1   fvdl 		ahd_free_scb(ahd, scb);
    486  1.1   fvdl 		ahd_unlock(ahd, &s);
    487  1.1   fvdl 		return;
    488  1.1   fvdl 	}
    489  1.1   fvdl 
    490  1.1   fvdl 	tinfo = ahd_fetch_transinfo(ahd, SCSIID_CHANNEL(ahd, scb->hscb->scsiid),
    491  1.1   fvdl 				    SCSIID_OUR_ID(scb->hscb->scsiid),
    492  1.1   fvdl 				    SCSIID_TARGET(ahd, scb->hscb->scsiid),
    493  1.1   fvdl 				    &tstate);
    494  1.1   fvdl 
    495  1.1   fvdl 	mask = SCB_GET_TARGET_MASK(ahd, scb);
    496  1.1   fvdl 
    497  1.1   fvdl 	if ((tstate->discenable & mask) != 0)
    498  1.1   fvdl 		scb->hscb->control |= DISCENB;
    499  1.1   fvdl 
    500  1.1   fvdl 	if ((tstate->tagenable & mask) != 0)
    501  1.1   fvdl 		scb->hscb->control |= xs->xs_tag_type|TAG_ENB;
    502  1.1   fvdl 
    503  1.1   fvdl 	if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU) != 0) {
    504  1.1   fvdl 		scb->flags |= SCB_PACKETIZED;
    505  1.1   fvdl 		if (scb->hscb->task_management != 0)
    506  1.1   fvdl 			scb->hscb->control &= ~MK_MESSAGE;
    507  1.1   fvdl 	}
    508  1.1   fvdl 
    509  1.1   fvdl 	if ((xs->xs_control & XS_CTL_DISCOVERY) &&
    510  1.1   fvdl 	    (tinfo->goal.width != 0
    511  1.1   fvdl 	     || tinfo->goal.period != 0
    512  1.1   fvdl 	     || tinfo->goal.ppr_options != 0)) {
    513  1.1   fvdl 		scb->flags |= SCB_NEGOTIATE;
    514  1.1   fvdl 		scb->hscb->control |= MK_MESSAGE;
    515  1.1   fvdl 	} else if ((tstate->auto_negotiate & mask) != 0) {
    516  1.1   fvdl 	  	scb->flags |= SCB_AUTO_NEGOTIATE;
    517  1.1   fvdl 		scb->hscb->control |= MK_MESSAGE;
    518  1.1   fvdl 	}
    519  1.1   fvdl 
    520  1.1   fvdl 	LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links);
    521  1.1   fvdl 
    522  1.1   fvdl 	scb->flags |= SCB_ACTIVE;
    523  1.1   fvdl 
    524  1.1   fvdl 	if (!(xs->xs_control & XS_CTL_POLL)) {
    525  1.1   fvdl 		callout_reset(&scb->xs->xs_callout, xs->timeout > 1000000 ?
    526  1.1   fvdl 			      (xs->timeout / 1000) * hz : (xs->timeout * hz) / 1000,
    527  1.1   fvdl 			      ahd_timeout, scb);
    528  1.1   fvdl 	}
    529  1.1   fvdl 
    530  1.1   fvdl 	if ((scb->flags & SCB_TARGET_IMMEDIATE) != 0) {
    531  1.1   fvdl 		/* Define a mapping from our tag to the SCB. */
    532  1.1   fvdl 		ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb;
    533  1.1   fvdl 		ahd_pause(ahd);
    534  1.1   fvdl 		ahd_set_scbptr(ahd, SCB_GET_TAG(scb));
    535  1.1   fvdl 		ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_TARG);
    536  1.1   fvdl 		ahd_unpause(ahd);
    537  1.1   fvdl 	} else {
    538  1.1   fvdl 		ahd_queue_scb(ahd, scb);
    539  1.1   fvdl 	}
    540  1.1   fvdl 
    541  1.1   fvdl 	if (!(xs->xs_control & XS_CTL_POLL)) {
    542  1.1   fvdl                 ahd_unlock(ahd, &s);
    543  1.1   fvdl                 return;
    544  1.1   fvdl         }
    545  1.1   fvdl         /*
    546  1.1   fvdl          * If we can't use interrupts, poll for completion
    547  1.1   fvdl          */
    548  1.1   fvdl         SC_DEBUG(xs->xs_periph, SCSIPI_DB3, ("cmd_poll\n"));
    549  1.1   fvdl         do {
    550  1.1   fvdl                 if (ahd_poll(ahd, xs->timeout)) {
    551  1.1   fvdl                         if (!(xs->xs_control & XS_CTL_SILENT))
    552  1.1   fvdl                                 printf("cmd fail\n");
    553  1.1   fvdl                         ahd_timeout(scb);
    554  1.1   fvdl                         break;
    555  1.1   fvdl                 }
    556  1.1   fvdl         } while (!(xs->xs_status & XS_STS_DONE));
    557  1.1   fvdl 
    558  1.1   fvdl 	ahd_unlock(ahd, &s);
    559  1.1   fvdl }
    560  1.1   fvdl 
    561  1.1   fvdl static int
    562  1.1   fvdl ahd_poll(struct ahd_softc *ahd, int wait)
    563  1.1   fvdl {
    564  1.1   fvdl 
    565  1.1   fvdl 	while (--wait) {
    566  1.1   fvdl                 DELAY(1000);
    567  1.1   fvdl                 if (ahd_inb(ahd, INTSTAT) & INT_PEND)
    568  1.1   fvdl                         break;
    569  1.1   fvdl         }
    570  1.1   fvdl 
    571  1.1   fvdl         if (wait == 0) {
    572  1.1   fvdl                 printf("%s: board is not responding\n", ahd_name(ahd));
    573  1.1   fvdl                 return (EIO);
    574  1.1   fvdl         }
    575  1.1   fvdl 
    576  1.1   fvdl         ahd_intr((void *)ahd);
    577  1.1   fvdl         return (0);
    578  1.1   fvdl }
    579  1.1   fvdl 
    580  1.1   fvdl 
    581  1.1   fvdl static void
    582  1.1   fvdl ahd_setup_data(struct ahd_softc *ahd, struct scsipi_xfer *xs,
    583  1.1   fvdl 	       struct scb *scb)
    584  1.1   fvdl {
    585  1.1   fvdl 	struct hardware_scb *hscb;
    586  1.1   fvdl 
    587  1.1   fvdl 	hscb = scb->hscb;
    588  1.1   fvdl 	xs->resid = xs->status = 0;
    589  1.1   fvdl 
    590  1.1   fvdl 	hscb->cdb_len = xs->cmdlen;
    591  1.1   fvdl 	if (hscb->cdb_len > MAX_CDB_LEN) {
    592  1.1   fvdl 		int s;
    593  1.1   fvdl 		/*
    594  1.1   fvdl 		 * Should CAM start to support CDB sizes
    595  1.1   fvdl 		 * greater than 16 bytes, we could use
    596  1.1   fvdl 		 * the sense buffer to store the CDB.
    597  1.1   fvdl 		 */
    598  1.1   fvdl 		ahd_set_transaction_status(scb,
    599  1.1   fvdl 					   XS_DRIVER_STUFFUP);
    600  1.1   fvdl 
    601  1.1   fvdl 		ahd_lock(ahd, &s);
    602  1.1   fvdl 		ahd_free_scb(ahd, scb);
    603  1.1   fvdl 		ahd_unlock(ahd, &s);
    604  1.1   fvdl 		scsipi_done(xs);
    605  1.1   fvdl 	}
    606  1.1   fvdl 	memcpy(hscb->shared_data.idata.cdb, xs->cmd, hscb->cdb_len);
    607  1.1   fvdl 
    608  1.1   fvdl 	/* Only use S/G if there is a transfer */
    609  1.1   fvdl         if (xs->datalen) {
    610  1.1   fvdl                 int error;
    611  1.1   fvdl 
    612  1.1   fvdl                 error = bus_dmamap_load(ahd->parent_dmat,
    613  1.1   fvdl 					scb->dmamap, xs->data,
    614  1.1   fvdl 					xs->datalen, NULL,
    615  1.1   fvdl 					((xs->xs_control & XS_CTL_NOSLEEP) ?
    616  1.1   fvdl 					 BUS_DMA_NOWAIT : BUS_DMA_WAITOK) |
    617  1.1   fvdl 					BUS_DMA_STREAMING |
    618  1.1   fvdl 					((xs->xs_control & XS_CTL_DATA_IN) ?
    619  1.1   fvdl 					 BUS_DMA_READ : BUS_DMA_WRITE));
    620  1.1   fvdl                 if (error) {
    621  1.1   fvdl #ifdef AHD_DEBUG
    622  1.1   fvdl                         printf("%s: in ahc_setup_data(): bus_dmamap_load() "
    623  1.1   fvdl 			       "= %d\n",
    624  1.1   fvdl 			       ahd_name(ahd), error);
    625  1.1   fvdl #endif
    626  1.1   fvdl                         xs->error = XS_RESOURCE_SHORTAGE;
    627  1.1   fvdl                         scsipi_done(xs);
    628  1.1   fvdl                         return;
    629  1.1   fvdl                 }
    630  1.1   fvdl                 ahd_execute_scb(scb,
    631  1.1   fvdl 				scb->dmamap->dm_segs,
    632  1.1   fvdl 				scb->dmamap->dm_nsegs);
    633  1.1   fvdl         } else {
    634  1.1   fvdl                 ahd_execute_scb(scb, NULL, 0);
    635  1.1   fvdl         }
    636  1.1   fvdl }
    637  1.1   fvdl 
    638  1.1   fvdl void
    639  1.1   fvdl ahd_timeout(void *arg)
    640  1.1   fvdl {
    641  1.1   fvdl 	struct	scb	  *scb;
    642  1.1   fvdl 	struct	ahd_softc *ahd;
    643  1.1   fvdl 	ahd_mode_state	   saved_modes;
    644  1.1   fvdl 	int		   s;
    645  1.1   fvdl 	int		   target;
    646  1.1   fvdl 	int		   lun;
    647  1.1   fvdl 	char		   channel;
    648  1.1   fvdl 
    649  1.1   fvdl 	scb = (struct scb *)arg;
    650  1.1   fvdl 	ahd = (struct ahd_softc *)scb->ahd_softc;
    651  1.1   fvdl 
    652  1.1   fvdl 	printf("%s: ahd_timeout\n", ahd_name(ahd));
    653  1.1   fvdl 
    654  1.1   fvdl 	ahd_lock(ahd, &s);
    655  1.1   fvdl 
    656  1.1   fvdl 	ahd_pause_and_flushwork(ahd);
    657  1.1   fvdl 	saved_modes = ahd_save_modes(ahd);
    658  1.1   fvdl #if 0
    659  1.1   fvdl 	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
    660  1.1   fvdl 	ahd_outb(ahd, SCSISIGO, ACKO);
    661  1.1   fvdl 	printf("set ACK\n");
    662  1.1   fvdl 	ahd_outb(ahd, SCSISIGO, 0);
    663  1.1   fvdl 	printf("clearing Ack\n");
    664  1.1   fvdl 	ahd_restore_modes(ahd, saved_modes);
    665  1.1   fvdl #endif
    666  1.1   fvdl 	if ((scb->flags & SCB_ACTIVE) == 0) {
    667  1.1   fvdl 		/* Previous timeout took care of me already */
    668  1.1   fvdl 		printf("%s: Timedout SCB already complete. "
    669  1.1   fvdl 		       "Interrupts may not be functioning.\n", ahd_name(ahd));
    670  1.1   fvdl 		ahd_unpause(ahd);
    671  1.1   fvdl 		ahd_unlock(ahd, &s);
    672  1.1   fvdl 		return;
    673  1.1   fvdl 	}
    674  1.1   fvdl 
    675  1.1   fvdl 	target = SCB_GET_TARGET(ahd, scb);
    676  1.1   fvdl 	channel = SCB_GET_CHANNEL(ahd, scb);
    677  1.1   fvdl 	lun = SCB_GET_LUN(scb);
    678  1.1   fvdl 
    679  1.1   fvdl 	ahd_print_path(ahd, scb);
    680  1.1   fvdl 	printf("SCB 0x%x - timed out\n", SCB_GET_TAG(scb));
    681  1.1   fvdl 	ahd_dump_card_state(ahd);
    682  1.1   fvdl 	ahd_reset_channel(ahd, SIM_CHANNEL(ahd, sim),
    683  1.1   fvdl 			  /*initiate reset*/TRUE);
    684  1.1   fvdl 	ahd_unlock(ahd, &s);
    685  1.1   fvdl 	return;
    686  1.1   fvdl }
    687  1.1   fvdl 
    688  1.1   fvdl int
    689  1.1   fvdl ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg)
    690  1.1   fvdl {
    691  1.1   fvdl 	ahd->platform_data = malloc(sizeof(struct ahd_platform_data), M_DEVBUF,
    692  1.1   fvdl 				    M_NOWAIT /*| M_ZERO*/);
    693  1.1   fvdl 	if (ahd->platform_data == NULL)
    694  1.1   fvdl 		return (ENOMEM);
    695  1.1   fvdl 
    696  1.1   fvdl 	memset(ahd->platform_data, 0, sizeof(struct ahd_platform_data));
    697  1.1   fvdl 
    698  1.1   fvdl 	return (0);
    699  1.1   fvdl }
    700  1.1   fvdl 
    701  1.1   fvdl void
    702  1.1   fvdl ahd_platform_free(struct ahd_softc *ahd)
    703  1.1   fvdl {
    704  1.1   fvdl 	free(ahd->platform_data, M_DEVBUF);
    705  1.1   fvdl }
    706  1.1   fvdl 
    707  1.1   fvdl int
    708  1.1   fvdl ahd_softc_comp(struct ahd_softc *lahd, struct ahd_softc *rahd)
    709  1.1   fvdl {
    710  1.1   fvdl 	/* We don't sort softcs under NetBSD so report equal always */
    711  1.1   fvdl 	return (0);
    712  1.1   fvdl }
    713  1.1   fvdl 
    714  1.1   fvdl int
    715  1.1   fvdl ahd_detach(struct device *self, int flags)
    716  1.1   fvdl {
    717  1.1   fvdl 	int rv = 0;
    718  1.1   fvdl 
    719  1.1   fvdl 	struct ahd_softc *ahd = (struct ahd_softc*)self;
    720  1.1   fvdl 
    721  1.1   fvdl 	if (ahd->sc_child != NULL)
    722  1.1   fvdl 		rv = config_detach((void *)ahd->sc_child, flags);
    723  1.1   fvdl 
    724  1.1   fvdl 	shutdownhook_disestablish(ahd->shutdown_hook);
    725  1.1   fvdl 
    726  1.1   fvdl 	ahd_free(ahd);
    727  1.1   fvdl 
    728  1.1   fvdl 	return rv;
    729  1.1   fvdl }
    730  1.1   fvdl 
    731  1.1   fvdl void
    732  1.1   fvdl ahd_platform_set_tags(struct ahd_softc *ahd,
    733  1.1   fvdl 		      struct ahd_devinfo *devinfo, ahd_queue_alg alg)
    734  1.1   fvdl {
    735  1.1   fvdl 	struct ahd_initiator_tinfo *tinfo;
    736  1.1   fvdl         struct ahd_tmode_tstate *tstate;
    737  1.1   fvdl 
    738  1.1   fvdl         tinfo = ahd_fetch_transinfo(ahd, devinfo->channel, devinfo->our_scsiid,
    739  1.1   fvdl                                     devinfo->target, &tstate);
    740  1.1   fvdl 
    741  1.1   fvdl         if (alg != AHD_QUEUE_NONE)
    742  1.1   fvdl                 tstate->tagenable |= devinfo->target_mask;
    743  1.1   fvdl 	else
    744  1.1   fvdl 	  	tstate->tagenable &= ~devinfo->target_mask;
    745  1.1   fvdl }
    746  1.1   fvdl 
    747  1.1   fvdl void
    748  1.1   fvdl ahd_send_async(struct ahd_softc *ahc, char channel, u_int target, u_int lun,
    749  1.1   fvdl 	       ac_code code, void *opt_arg)
    750  1.1   fvdl {
    751  1.1   fvdl 	struct ahd_tmode_tstate *tstate;
    752  1.1   fvdl 	struct ahd_initiator_tinfo *tinfo;
    753  1.1   fvdl 	struct ahd_devinfo devinfo;
    754  1.1   fvdl 	struct scsipi_channel *chan;
    755  1.1   fvdl 	struct scsipi_xfer_mode xm;
    756  1.1   fvdl 
    757  1.1   fvdl #ifdef DIAGNOSTIC
    758  1.1   fvdl 	if (channel != 'A')
    759  1.1   fvdl 		panic("ahd_send_async: not channel A");
    760  1.1   fvdl #endif
    761  1.1   fvdl 	chan = &ahc->sc_channel;
    762  1.1   fvdl 	switch (code) {
    763  1.1   fvdl 	case AC_TRANSFER_NEG:
    764  1.1   fvdl 		tinfo = ahd_fetch_transinfo(ahc, channel, ahc->our_id, target,
    765  1.1   fvdl 			    &tstate);
    766  1.1   fvdl 		ahd_compile_devinfo(&devinfo, ahc->our_id, target, lun,
    767  1.1   fvdl 		    channel, ROLE_UNKNOWN);
    768  1.1   fvdl 		/*
    769  1.1   fvdl 		 * Don't bother if negotiating. XXX?
    770  1.1   fvdl 		 */
    771  1.1   fvdl 		if (tinfo->curr.period != tinfo->goal.period
    772  1.1   fvdl 		    || tinfo->curr.width != tinfo->goal.width
    773  1.1   fvdl 		    || tinfo->curr.offset != tinfo->goal.offset
    774  1.1   fvdl 		    || tinfo->curr.ppr_options != tinfo->goal.ppr_options)
    775  1.1   fvdl 			break;
    776  1.1   fvdl 		xm.xm_target = target;
    777  1.1   fvdl 		xm.xm_mode = 0;
    778  1.1   fvdl 		xm.xm_period = tinfo->curr.period;
    779  1.1   fvdl 		xm.xm_offset = tinfo->curr.offset;
    780  1.1   fvdl 		if (tinfo->goal.ppr_options & MSG_EXT_PPR_DT_REQ)
    781  1.1   fvdl 			xm.xm_mode |= PERIPH_CAP_DT;
    782  1.1   fvdl 		if (tinfo->curr.width == MSG_EXT_WDTR_BUS_16_BIT)
    783  1.1   fvdl 			xm.xm_mode |= PERIPH_CAP_WIDE16;
    784  1.1   fvdl 		if (tinfo->curr.period)
    785  1.1   fvdl 			xm.xm_mode |= PERIPH_CAP_SYNC;
    786  1.1   fvdl 		if (tstate->tagenable & devinfo.target_mask)
    787  1.1   fvdl 			xm.xm_mode |= PERIPH_CAP_TQING;
    788  1.1   fvdl 		scsipi_async_event(chan, ASYNC_EVENT_XFER_MODE, &xm);
    789  1.1   fvdl 		break;
    790  1.1   fvdl 	case AC_BUS_RESET:
    791  1.1   fvdl 		scsipi_async_event(chan, ASYNC_EVENT_RESET, NULL);
    792  1.1   fvdl 	case AC_SENT_BDR:
    793  1.1   fvdl 	default:
    794  1.1   fvdl 		break;
    795  1.1   fvdl 	}
    796  1.1   fvdl }
    797