Home | History | Annotate | Line # | Download | only in ic
icp.c revision 1.29.22.1
      1  1.29.22.1     rmind /*	$NetBSD: icp.c,v 1.29.22.1 2011/03/05 20:53:16 rmind Exp $	*/
      2        1.1        ad 
      3        1.1        ad /*-
      4        1.8   thorpej  * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
      5        1.1        ad  * All rights reserved.
      6        1.1        ad  *
      7        1.1        ad  * This code is derived from software contributed to The NetBSD Foundation
      8        1.8   thorpej  * by Andrew Doran, and by Jason R. Thorpe of Wasabi Systems, Inc.
      9        1.1        ad  *
     10        1.1        ad  * Redistribution and use in source and binary forms, with or without
     11        1.1        ad  * modification, are permitted provided that the following conditions
     12        1.1        ad  * are met:
     13        1.1        ad  * 1. Redistributions of source code must retain the above copyright
     14        1.1        ad  *    notice, this list of conditions and the following disclaimer.
     15        1.1        ad  * 2. Redistributions in binary form must reproduce the above copyright
     16        1.1        ad  *    notice, this list of conditions and the following disclaimer in the
     17        1.1        ad  *    documentation and/or other materials provided with the distribution.
     18        1.1        ad  *
     19        1.1        ad  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20        1.1        ad  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21        1.1        ad  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22        1.1        ad  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23        1.1        ad  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24        1.1        ad  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25        1.1        ad  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26        1.1        ad  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27        1.1        ad  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28        1.1        ad  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29        1.1        ad  * POSSIBILITY OF SUCH DAMAGE.
     30        1.1        ad  */
     31        1.1        ad 
     32        1.1        ad /*
     33        1.1        ad  * Copyright (c) 1999, 2000 Niklas Hallqvist.  All rights reserved.
     34        1.1        ad  *
     35        1.1        ad  * Redistribution and use in source and binary forms, with or without
     36        1.1        ad  * modification, are permitted provided that the following conditions
     37        1.1        ad  * are met:
     38        1.1        ad  * 1. Redistributions of source code must retain the above copyright
     39        1.1        ad  *    notice, this list of conditions and the following disclaimer.
     40        1.1        ad  * 2. Redistributions in binary form must reproduce the above copyright
     41        1.1        ad  *    notice, this list of conditions and the following disclaimer in the
     42        1.1        ad  *    documentation and/or other materials provided with the distribution.
     43        1.1        ad  * 3. All advertising materials mentioning features or use of this software
     44        1.1        ad  *    must display the following acknowledgement:
     45        1.1        ad  *	This product includes software developed by Niklas Hallqvist.
     46        1.1        ad  * 4. The name of the author may not be used to endorse or promote products
     47        1.1        ad  *    derived from this software without specific prior written permission.
     48        1.1        ad  *
     49        1.1        ad  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     50        1.1        ad  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     51        1.1        ad  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     52        1.1        ad  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     53        1.1        ad  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     54        1.1        ad   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     55        1.1        ad  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     56        1.1        ad  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     57        1.1        ad  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     58        1.1        ad  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     59        1.1        ad  *
     60        1.1        ad  * from OpenBSD: gdt_common.c,v 1.12 2001/07/04 06:43:18 niklas Exp
     61        1.1        ad  */
     62        1.1        ad 
     63        1.1        ad /*
     64        1.1        ad  * This driver would not have written if it was not for the hardware donations
     65        1.1        ad  * from both ICP-Vortex and ko.neT.  I want to thank them for their support.
     66        1.1        ad  *
     67        1.1        ad  * Re-worked for NetBSD by Andrew Doran.  Test hardware kindly supplied by
     68        1.1        ad  * Intel.
     69        1.8   thorpej  *
     70        1.8   thorpej  * Support for the ICP-Vortex management tools added by
     71        1.8   thorpej  * Jason R. Thorpe of Wasabi Systems, Inc., based on code
     72       1.10   thorpej  * provided by Achim Leubner <achim.leubner (at) intel.com>.
     73       1.10   thorpej  *
     74       1.10   thorpej  * Additional support for dynamic rescan of cacheservice drives by
     75       1.10   thorpej  * Jason R. Thorpe of Wasabi Systems, Inc.
     76        1.1        ad  */
     77        1.1        ad 
     78        1.1        ad #include <sys/cdefs.h>
     79  1.29.22.1     rmind __KERNEL_RCSID(0, "$NetBSD: icp.c,v 1.29.22.1 2011/03/05 20:53:16 rmind Exp $");
     80        1.1        ad 
     81        1.1        ad #include <sys/param.h>
     82        1.1        ad #include <sys/systm.h>
     83        1.1        ad #include <sys/kernel.h>
     84        1.1        ad #include <sys/device.h>
     85        1.1        ad #include <sys/queue.h>
     86        1.1        ad #include <sys/proc.h>
     87        1.1        ad #include <sys/buf.h>
     88        1.1        ad #include <sys/endian.h>
     89        1.1        ad #include <sys/malloc.h>
     90        1.1        ad #include <sys/disk.h>
     91        1.1        ad 
     92       1.18       dsl #include <sys/bswap.h>
     93       1.26        ad #include <sys/bus.h>
     94        1.1        ad 
     95        1.1        ad #include <dev/pci/pcireg.h>
     96        1.1        ad #include <dev/pci/pcivar.h>
     97        1.1        ad #include <dev/pci/pcidevs.h>
     98        1.1        ad 
     99        1.1        ad #include <dev/ic/icpreg.h>
    100        1.1        ad #include <dev/ic/icpvar.h>
    101        1.1        ad 
    102        1.8   thorpej #include <dev/scsipi/scsipi_all.h>
    103        1.8   thorpej #include <dev/scsipi/scsiconf.h>
    104        1.8   thorpej 
    105       1.13  drochner #include "locators.h"
    106       1.13  drochner 
    107        1.1        ad int	icp_async_event(struct icp_softc *, int);
    108        1.1        ad void	icp_ccb_submit(struct icp_softc *icp, struct icp_ccb *ic);
    109        1.1        ad void	icp_chain(struct icp_softc *);
    110        1.1        ad int	icp_print(void *, const char *);
    111        1.1        ad void	icp_watchdog(void *);
    112        1.8   thorpej void	icp_ucmd_intr(struct icp_ccb *);
    113       1.10   thorpej void	icp_recompute_openings(struct icp_softc *);
    114        1.8   thorpej 
    115        1.8   thorpej int	icp_count;	/* total # of controllers, for ioctl interface */
    116        1.8   thorpej 
    117        1.8   thorpej /*
    118        1.8   thorpej  * Statistics for the ioctl interface to query.
    119        1.8   thorpej  *
    120        1.8   thorpej  * XXX Global.  They should probably be made per-controller
    121        1.8   thorpej  * XXX at some point.
    122        1.8   thorpej  */
    123        1.8   thorpej gdt_statist_t icp_stats;
    124        1.1        ad 
    125        1.1        ad int
    126        1.1        ad icp_init(struct icp_softc *icp, const char *intrstr)
    127        1.1        ad {
    128        1.1        ad 	struct icp_attach_args icpa;
    129        1.1        ad 	struct icp_binfo binfo;
    130        1.1        ad 	struct icp_ccb *ic;
    131        1.1        ad 	u_int16_t cdev_cnt;
    132       1.12   mycroft 	int i, j, state, feat, nsegs, rv;
    133       1.15  drochner 	int locs[ICPCF_NLOCS];
    134        1.1        ad 
    135        1.5    simonb 	state = 0;
    136        1.1        ad 
    137        1.1        ad 	if (intrstr != NULL)
    138       1.27    cegger 		aprint_normal_dev(&icp->icp_dv, "interrupting at %s\n",
    139        1.1        ad 		    intrstr);
    140        1.1        ad 
    141        1.1        ad 	SIMPLEQ_INIT(&icp->icp_ccb_queue);
    142        1.1        ad 	SIMPLEQ_INIT(&icp->icp_ccb_freelist);
    143        1.8   thorpej 	SIMPLEQ_INIT(&icp->icp_ucmd_queue);
    144       1.25        ad 	callout_init(&icp->icp_wdog_callout, 0);
    145        1.1        ad 
    146        1.1        ad 	/*
    147        1.1        ad 	 * Allocate a scratch area.
    148        1.1        ad 	 */
    149        1.1        ad 	if (bus_dmamap_create(icp->icp_dmat, ICP_SCRATCH_SIZE, 1,
    150        1.1        ad 	    ICP_SCRATCH_SIZE, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
    151        1.1        ad 	    &icp->icp_scr_dmamap) != 0) {
    152       1.27    cegger 		aprint_error_dev(&icp->icp_dv, "cannot create scratch dmamap\n");
    153        1.1        ad 		return (1);
    154        1.1        ad 	}
    155        1.1        ad 	state++;
    156        1.1        ad 
    157        1.1        ad 	if (bus_dmamem_alloc(icp->icp_dmat, ICP_SCRATCH_SIZE, PAGE_SIZE, 0,
    158        1.1        ad 	    icp->icp_scr_seg, 1, &nsegs, BUS_DMA_NOWAIT) != 0) {
    159       1.27    cegger 		aprint_error_dev(&icp->icp_dv, "cannot alloc scratch dmamem\n");
    160        1.1        ad 		goto bail_out;
    161        1.1        ad 	}
    162        1.1        ad 	state++;
    163        1.1        ad 
    164        1.1        ad 	if (bus_dmamem_map(icp->icp_dmat, icp->icp_scr_seg, nsegs,
    165        1.1        ad 	    ICP_SCRATCH_SIZE, &icp->icp_scr, 0)) {
    166       1.27    cegger 		aprint_error_dev(&icp->icp_dv, "cannot map scratch dmamem\n");
    167        1.1        ad 		goto bail_out;
    168        1.1        ad 	}
    169        1.1        ad 	state++;
    170        1.1        ad 
    171        1.1        ad 	if (bus_dmamap_load(icp->icp_dmat, icp->icp_scr_dmamap, icp->icp_scr,
    172        1.1        ad 	    ICP_SCRATCH_SIZE, NULL, BUS_DMA_NOWAIT)) {
    173       1.27    cegger 		aprint_error_dev(&icp->icp_dv, "cannot load scratch dmamap\n");
    174        1.1        ad 		goto bail_out;
    175        1.1        ad 	}
    176        1.1        ad 	state++;
    177        1.1        ad 
    178        1.1        ad 	/*
    179        1.1        ad 	 * Allocate and initialize the command control blocks.
    180        1.1        ad 	 */
    181        1.1        ad 	ic = malloc(sizeof(*ic) * ICP_NCCBS, M_DEVBUF, M_NOWAIT | M_ZERO);
    182        1.1        ad 	if ((icp->icp_ccbs = ic) == NULL) {
    183       1.27    cegger 		aprint_error_dev(&icp->icp_dv, "malloc() failed\n");
    184        1.1        ad 		goto bail_out;
    185        1.1        ad 	}
    186        1.1        ad 	state++;
    187        1.1        ad 
    188        1.1        ad 	for (i = 0; i < ICP_NCCBS; i++, ic++) {
    189        1.1        ad 		/*
    190        1.1        ad 		 * The first two command indexes have special meanings, so
    191        1.1        ad 		 * we can't use them.
    192        1.1        ad 		 */
    193        1.1        ad 		ic->ic_ident = i + 2;
    194        1.1        ad 		rv = bus_dmamap_create(icp->icp_dmat, ICP_MAX_XFER,
    195        1.1        ad 		    ICP_MAXSG, ICP_MAX_XFER, 0,
    196        1.1        ad 		    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
    197        1.1        ad 		    &ic->ic_xfer_map);
    198        1.1        ad 		if (rv != 0)
    199        1.1        ad 			break;
    200        1.1        ad 		icp->icp_nccbs++;
    201        1.1        ad 		icp_ccb_free(icp, ic);
    202        1.1        ad 	}
    203        1.1        ad #ifdef DIAGNOSTIC
    204        1.1        ad 	if (icp->icp_nccbs != ICP_NCCBS)
    205       1.27    cegger 		aprint_error_dev(&icp->icp_dv, "%d/%d CCBs usable\n",
    206        1.1        ad 		    icp->icp_nccbs, ICP_NCCBS);
    207        1.1        ad #endif
    208        1.1        ad 
    209        1.1        ad 	/*
    210        1.1        ad 	 * Initalize the controller.
    211        1.1        ad 	 */
    212        1.1        ad 	if (!icp_cmd(icp, ICP_SCREENSERVICE, ICP_INIT, 0, 0, 0)) {
    213       1.27    cegger 		aprint_error_dev(&icp->icp_dv, "screen service init error %d\n",
    214       1.27    cegger 		    icp->icp_status);
    215        1.1        ad 		goto bail_out;
    216        1.1        ad 	}
    217        1.1        ad 
    218        1.1        ad 	if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INIT, ICP_LINUX_OS, 0, 0)) {
    219       1.27    cegger 		aprint_error_dev(&icp->icp_dv, "cache service init error %d\n",
    220       1.27    cegger 		    icp->icp_status);
    221        1.1        ad 		goto bail_out;
    222        1.1        ad 	}
    223        1.1        ad 
    224        1.1        ad 	icp_cmd(icp, ICP_CACHESERVICE, ICP_UNFREEZE_IO, 0, 0, 0);
    225        1.1        ad 
    226        1.1        ad 	if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_MOUNT, 0xffff, 1, 0)) {
    227       1.27    cegger 		aprint_error_dev(&icp->icp_dv, "cache service mount error %d\n",
    228       1.27    cegger 		    icp->icp_status);
    229        1.1        ad 		goto bail_out;
    230        1.1        ad 	}
    231        1.1        ad 
    232        1.1        ad 	if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INIT, ICP_LINUX_OS, 0, 0)) {
    233       1.27    cegger 		aprint_error_dev(&icp->icp_dv, "cache service post-mount init error %d\n",
    234       1.27    cegger 		    icp->icp_status);
    235        1.1        ad 		goto bail_out;
    236        1.1        ad 	}
    237        1.1        ad 	cdev_cnt = (u_int16_t)icp->icp_info;
    238        1.8   thorpej 	icp->icp_fw_vers = icp->icp_service;
    239        1.1        ad 
    240        1.1        ad 	if (!icp_cmd(icp, ICP_SCSIRAWSERVICE, ICP_INIT, 0, 0, 0)) {
    241       1.27    cegger 		aprint_error_dev(&icp->icp_dv, "raw service init error %d\n",
    242       1.27    cegger 		    icp->icp_status);
    243        1.1        ad 		goto bail_out;
    244        1.1        ad 	}
    245        1.1        ad 
    246        1.1        ad 	/*
    247        1.1        ad 	 * Set/get raw service features (scatter/gather).
    248        1.1        ad 	 */
    249        1.1        ad 	feat = 0;
    250        1.1        ad 	if (icp_cmd(icp, ICP_SCSIRAWSERVICE, ICP_SET_FEAT, ICP_SCATTER_GATHER,
    251        1.1        ad 	    0, 0))
    252        1.1        ad 		if (icp_cmd(icp, ICP_SCSIRAWSERVICE, ICP_GET_FEAT, 0, 0, 0))
    253        1.1        ad 			feat = icp->icp_info;
    254        1.1        ad 
    255        1.1        ad 	if ((feat & ICP_SCATTER_GATHER) == 0) {
    256        1.1        ad #ifdef DIAGNOSTIC
    257       1.27    cegger 		aprint_normal_dev(&icp->icp_dv,
    258       1.27    cegger 		    "scatter/gather not supported (raw service)\n");
    259        1.1        ad #endif
    260       1.10   thorpej 	} else
    261       1.10   thorpej 		icp->icp_features |= ICP_FEAT_RAWSERVICE;
    262        1.1        ad 
    263        1.1        ad 	/*
    264        1.1        ad 	 * Set/get cache service features (scatter/gather).
    265        1.1        ad 	 */
    266        1.1        ad 	feat = 0;
    267        1.1        ad 	if (icp_cmd(icp, ICP_CACHESERVICE, ICP_SET_FEAT, 0,
    268        1.1        ad 	    ICP_SCATTER_GATHER, 0))
    269        1.1        ad 		if (icp_cmd(icp, ICP_CACHESERVICE, ICP_GET_FEAT, 0, 0, 0))
    270        1.1        ad 			feat = icp->icp_info;
    271        1.1        ad 
    272        1.1        ad 	if ((feat & ICP_SCATTER_GATHER) == 0) {
    273        1.1        ad #ifdef DIAGNOSTIC
    274       1.27    cegger 		aprint_normal_dev(&icp->icp_dv,
    275       1.27    cegger 		    "scatter/gather not supported (cache service)\n");
    276        1.1        ad #endif
    277       1.10   thorpej 	} else
    278       1.10   thorpej 		icp->icp_features |= ICP_FEAT_CACHESERVICE;
    279        1.1        ad 
    280        1.1        ad 	/*
    281        1.1        ad 	 * Pull some information from the board and dump.
    282        1.1        ad 	 */
    283        1.1        ad 	if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_IOCTL, ICP_BOARD_INFO,
    284        1.1        ad 	    ICP_INVALID_CHANNEL, sizeof(struct icp_binfo))) {
    285       1.27    cegger 		aprint_error_dev(&icp->icp_dv, "unable to retrive board info\n");
    286        1.1        ad 		goto bail_out;
    287        1.1        ad 	}
    288        1.1        ad 	memcpy(&binfo, icp->icp_scr, sizeof(binfo));
    289        1.1        ad 
    290       1.27    cegger 	aprint_normal_dev(&icp->icp_dv,
    291       1.27    cegger 	    "model <%s>, firmware <%s>, %d channel(s), %dMB memory\n",
    292       1.27    cegger 	    binfo.bi_type_string, binfo.bi_raid_string,
    293        1.1        ad 	    binfo.bi_chan_count, le32toh(binfo.bi_memsize) >> 20);
    294        1.1        ad 
    295        1.1        ad 	/*
    296        1.1        ad 	 * Determine the number of devices, and number of openings per
    297        1.1        ad 	 * device.
    298        1.1        ad 	 */
    299       1.10   thorpej 	if (icp->icp_features & ICP_FEAT_CACHESERVICE) {
    300        1.1        ad 		for (j = 0; j < cdev_cnt && j < ICP_MAX_HDRIVES; j++) {
    301        1.1        ad 			if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INFO, j, 0,
    302        1.1        ad 			    0))
    303        1.1        ad 				continue;
    304        1.1        ad 
    305        1.1        ad 			icp->icp_cdr[j].cd_size = icp->icp_info;
    306       1.10   thorpej 			if (icp->icp_cdr[j].cd_size != 0)
    307       1.10   thorpej 				icp->icp_ndevs++;
    308        1.1        ad 
    309        1.1        ad 			if (icp_cmd(icp, ICP_CACHESERVICE, ICP_DEVTYPE, j, 0,
    310        1.1        ad 			    0))
    311        1.1        ad 				icp->icp_cdr[j].cd_type = icp->icp_info;
    312        1.1        ad 		}
    313        1.1        ad 	}
    314        1.1        ad 
    315       1.10   thorpej 	if (icp->icp_features & ICP_FEAT_RAWSERVICE) {
    316       1.10   thorpej 		icp->icp_nchan = binfo.bi_chan_count;
    317       1.10   thorpej 		icp->icp_ndevs += icp->icp_nchan;
    318       1.10   thorpej 	}
    319        1.1        ad 
    320       1.10   thorpej 	icp_recompute_openings(icp);
    321        1.1        ad 
    322        1.1        ad 	/*
    323        1.1        ad 	 * Attach SCSI channels.
    324        1.1        ad 	 */
    325       1.10   thorpej 	if (icp->icp_features & ICP_FEAT_RAWSERVICE) {
    326        1.1        ad 		struct icp_ioc_version *iv;
    327        1.1        ad 		struct icp_rawioc *ri;
    328        1.1        ad 		struct icp_getch *gc;
    329        1.1        ad 
    330        1.1        ad 		iv = (struct icp_ioc_version *)icp->icp_scr;
    331        1.1        ad 		iv->iv_version = htole32(ICP_IOC_NEWEST);
    332        1.1        ad 		iv->iv_listents = ICP_MAXBUS;
    333        1.1        ad 		iv->iv_firstchan = 0;
    334        1.1        ad 		iv->iv_lastchan = ICP_MAXBUS - 1;
    335        1.1        ad 		iv->iv_listoffset = htole32(sizeof(*iv));
    336        1.1        ad 
    337        1.1        ad 		if (icp_cmd(icp, ICP_CACHESERVICE, ICP_IOCTL,
    338        1.1        ad 		    ICP_IOCHAN_RAW_DESC, ICP_INVALID_CHANNEL,
    339        1.1        ad 		    sizeof(*iv) + ICP_MAXBUS * sizeof(*ri))) {
    340        1.1        ad 			ri = (struct icp_rawioc *)(iv + 1);
    341        1.1        ad 			for (j = 0; j < binfo.bi_chan_count; j++, ri++)
    342        1.1        ad 				icp->icp_bus_id[j] = ri->ri_procid;
    343        1.1        ad 		} else {
    344        1.1        ad 			/*
    345        1.1        ad 			 * Fall back to the old method.
    346        1.1        ad 			 */
    347        1.1        ad 			gc = (struct icp_getch *)icp->icp_scr;
    348        1.1        ad 
    349       1.12   mycroft 			for (j = 0; j < binfo.bi_chan_count; j++) {
    350        1.1        ad 				if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_IOCTL,
    351        1.1        ad 				    ICP_SCSI_CHAN_CNT | ICP_L_CTRL_PATTERN,
    352        1.1        ad 				    ICP_IO_CHANNEL | ICP_INVALID_CHANNEL,
    353        1.1        ad 				    sizeof(*gc))) {
    354       1.27    cegger 				    	aprint_error_dev(&icp->icp_dv,
    355       1.27    cegger 					    "unable to get chan info");
    356        1.1        ad 					goto bail_out;
    357        1.1        ad 				}
    358        1.1        ad 				icp->icp_bus_id[j] = gc->gc_scsiid;
    359        1.1        ad 			}
    360        1.1        ad 		}
    361        1.1        ad 
    362        1.1        ad 		for (j = 0; j < binfo.bi_chan_count; j++) {
    363        1.1        ad 			if (icp->icp_bus_id[j] > ICP_MAXID_FC)
    364        1.1        ad 				icp->icp_bus_id[j] = ICP_MAXID_FC;
    365        1.1        ad 
    366        1.1        ad 			icpa.icpa_unit = j + ICPA_UNIT_SCSI;
    367       1.13  drochner 
    368       1.15  drochner 			locs[ICPCF_UNIT] = j + ICPA_UNIT_SCSI;
    369       1.13  drochner 
    370       1.10   thorpej 			icp->icp_children[icpa.icpa_unit] =
    371       1.15  drochner 				config_found_sm_loc(&icp->icp_dv, "icp", locs,
    372       1.16  drochner 					&icpa, icp_print, config_stdsubmatch);
    373        1.1        ad 		}
    374        1.1        ad 	}
    375        1.1        ad 
    376        1.1        ad 	/*
    377        1.1        ad 	 * Attach cache devices.
    378        1.1        ad 	 */
    379       1.10   thorpej 	if (icp->icp_features & ICP_FEAT_CACHESERVICE) {
    380        1.1        ad 		for (j = 0; j < cdev_cnt && j < ICP_MAX_HDRIVES; j++) {
    381        1.1        ad 			if (icp->icp_cdr[j].cd_size == 0)
    382        1.1        ad 				continue;
    383       1.14     perry 
    384        1.1        ad 			icpa.icpa_unit = j;
    385       1.13  drochner 
    386       1.15  drochner 			locs[ICPCF_UNIT] = j;
    387       1.13  drochner 
    388       1.10   thorpej 			icp->icp_children[icpa.icpa_unit] =
    389       1.15  drochner 			    config_found_sm_loc(&icp->icp_dv, "icp", locs,
    390       1.16  drochner 				&icpa, icp_print, config_stdsubmatch);
    391        1.1        ad 		}
    392        1.1        ad 	}
    393        1.1        ad 
    394        1.1        ad 	/*
    395        1.1        ad 	 * Start the watchdog.
    396        1.1        ad 	 */
    397        1.1        ad 	icp_watchdog(icp);
    398        1.8   thorpej 
    399        1.8   thorpej 	/*
    400        1.8   thorpej 	 * Count the controller, and we're done!
    401        1.8   thorpej 	 */
    402       1.24        ad 	if (icp_count++ == 0)
    403       1.24        ad 		mutex_init(&icp_ioctl_mutex, MUTEX_DEFAULT, IPL_NONE);
    404        1.8   thorpej 
    405        1.1        ad 	return (0);
    406        1.1        ad 
    407        1.1        ad  bail_out:
    408        1.1        ad 	if (state > 4)
    409        1.1        ad 		for (j = 0; j < i; j++)
    410        1.1        ad 			bus_dmamap_destroy(icp->icp_dmat,
    411        1.1        ad 			    icp->icp_ccbs[j].ic_xfer_map);
    412        1.1        ad  	if (state > 3)
    413        1.1        ad 		free(icp->icp_ccbs, M_DEVBUF);
    414        1.1        ad 	if (state > 2)
    415        1.1        ad 		bus_dmamap_unload(icp->icp_dmat, icp->icp_scr_dmamap);
    416        1.1        ad 	if (state > 1)
    417        1.1        ad 		bus_dmamem_unmap(icp->icp_dmat, icp->icp_scr,
    418        1.1        ad 		    ICP_SCRATCH_SIZE);
    419        1.1        ad 	if (state > 0)
    420        1.1        ad 		bus_dmamem_free(icp->icp_dmat, icp->icp_scr_seg, nsegs);
    421        1.1        ad 	bus_dmamap_destroy(icp->icp_dmat, icp->icp_scr_dmamap);
    422        1.1        ad 
    423        1.1        ad 	return (1);
    424        1.1        ad }
    425        1.1        ad 
    426        1.1        ad void
    427       1.10   thorpej icp_register_servicecb(struct icp_softc *icp, int unit,
    428       1.10   thorpej     const struct icp_servicecb *cb)
    429       1.10   thorpej {
    430       1.10   thorpej 
    431       1.10   thorpej 	icp->icp_servicecb[unit] = cb;
    432       1.10   thorpej }
    433       1.10   thorpej 
    434       1.10   thorpej void
    435       1.10   thorpej icp_rescan(struct icp_softc *icp, int unit)
    436       1.10   thorpej {
    437       1.10   thorpej 	struct icp_attach_args icpa;
    438       1.10   thorpej 	u_int newsize, newtype;
    439       1.15  drochner 	int locs[ICPCF_NLOCS];
    440       1.10   thorpej 
    441       1.10   thorpej 	/*
    442       1.10   thorpej 	 * NOTE: It is very important that the queue be frozen and not
    443       1.10   thorpej 	 * commands running when this is called.  The ioctl mutex must
    444       1.10   thorpej 	 * also be held.
    445       1.10   thorpej 	 */
    446       1.10   thorpej 
    447       1.10   thorpej 	KASSERT(icp->icp_qfreeze != 0);
    448       1.10   thorpej 	KASSERT(icp->icp_running == 0);
    449       1.10   thorpej 	KASSERT(unit < ICP_MAX_HDRIVES);
    450       1.10   thorpej 
    451       1.10   thorpej 	if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INFO, unit, 0, 0)) {
    452       1.10   thorpej #ifdef ICP_DEBUG
    453       1.10   thorpej 		printf("%s: rescan: unit %d ICP_INFO failed -> 0x%04x\n",
    454       1.27    cegger 		    device_xname(&icp->icp_dv), unit, icp->icp_status);
    455       1.10   thorpej #endif
    456       1.10   thorpej 		goto gone;
    457       1.10   thorpej 	}
    458       1.10   thorpej 	if ((newsize = icp->icp_info) == 0) {
    459       1.10   thorpej #ifdef ICP_DEBUG
    460       1.10   thorpej 		printf("%s: rescan: unit %d has zero size\n",
    461       1.29        ad 		    device_xname(&icp->icp_dv), unit);
    462       1.10   thorpej #endif
    463       1.10   thorpej  gone:
    464       1.10   thorpej 		/*
    465       1.10   thorpej 		 * Host drive is no longer present; detach if a child
    466       1.10   thorpej 		 * is currently there.
    467       1.10   thorpej 		 */
    468       1.10   thorpej 		if (icp->icp_cdr[unit].cd_size != 0)
    469       1.10   thorpej 			icp->icp_ndevs--;
    470       1.10   thorpej 		icp->icp_cdr[unit].cd_size = 0;
    471       1.10   thorpej 		if (icp->icp_children[unit] != NULL) {
    472       1.10   thorpej 			(void) config_detach(icp->icp_children[unit],
    473       1.10   thorpej 			    DETACH_FORCE);
    474       1.10   thorpej 			icp->icp_children[unit] = NULL;
    475       1.10   thorpej 		}
    476       1.10   thorpej 		return;
    477       1.10   thorpej 	}
    478       1.10   thorpej 
    479       1.10   thorpej 	if (icp_cmd(icp, ICP_CACHESERVICE, ICP_DEVTYPE, unit, 0, 0))
    480       1.10   thorpej 		newtype = icp->icp_info;
    481       1.10   thorpej 	else {
    482       1.10   thorpej #ifdef ICP_DEBUG
    483       1.10   thorpej 		printf("%s: rescan: unit %d ICP_DEVTYPE failed\n",
    484       1.27    cegger 		    device_xname(&icp->icp_dv), unit);
    485       1.10   thorpej #endif
    486       1.10   thorpej 		newtype = 0;	/* XXX? */
    487       1.10   thorpej 	}
    488       1.10   thorpej 
    489       1.10   thorpej #ifdef ICP_DEBUG
    490       1.10   thorpej 	printf("%s: rescan: unit %d old %u/%u, new %u/%u\n",
    491       1.27    cegger 	    device_xname(&icp->icp_dv), unit, icp->icp_cdr[unit].cd_size,
    492       1.10   thorpej 	    icp->icp_cdr[unit].cd_type, newsize, newtype);
    493       1.10   thorpej #endif
    494       1.10   thorpej 
    495       1.10   thorpej 	/*
    496       1.10   thorpej 	 * If the type or size changed, detach any old child (if it exists)
    497       1.10   thorpej 	 * and attach a new one.
    498       1.10   thorpej 	 */
    499       1.10   thorpej 	if (icp->icp_children[unit] == NULL ||
    500       1.10   thorpej 	    newsize != icp->icp_cdr[unit].cd_size ||
    501       1.10   thorpej 	    newtype != icp->icp_cdr[unit].cd_type) {
    502       1.10   thorpej 		if (icp->icp_cdr[unit].cd_size == 0)
    503       1.10   thorpej 			icp->icp_ndevs++;
    504       1.10   thorpej 		icp->icp_cdr[unit].cd_size = newsize;
    505       1.10   thorpej 		icp->icp_cdr[unit].cd_type = newtype;
    506       1.10   thorpej 		if (icp->icp_children[unit] != NULL)
    507       1.10   thorpej 			(void) config_detach(icp->icp_children[unit],
    508       1.10   thorpej 			    DETACH_FORCE);
    509       1.10   thorpej 
    510       1.10   thorpej 		icpa.icpa_unit = unit;
    511       1.13  drochner 
    512       1.15  drochner 		locs[ICPCF_UNIT] = unit;
    513       1.13  drochner 
    514       1.13  drochner 		icp->icp_children[unit] = config_found_sm_loc(&icp->icp_dv,
    515       1.16  drochner 			"icp", locs, &icpa, icp_print, config_stdsubmatch);
    516       1.10   thorpej 	}
    517       1.10   thorpej 
    518       1.10   thorpej 	icp_recompute_openings(icp);
    519       1.10   thorpej }
    520       1.10   thorpej 
    521       1.10   thorpej void
    522       1.10   thorpej icp_rescan_all(struct icp_softc *icp)
    523       1.10   thorpej {
    524       1.10   thorpej 	int unit;
    525       1.10   thorpej 	u_int16_t cdev_cnt;
    526       1.10   thorpej 
    527       1.10   thorpej 	/*
    528       1.10   thorpej 	 * This is the old method of rescanning the host drives.  We
    529       1.10   thorpej 	 * start by reinitializing the cache service.
    530       1.10   thorpej 	 */
    531       1.10   thorpej 	if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INIT, ICP_LINUX_OS, 0, 0)) {
    532       1.10   thorpej 		printf("%s: unable to re-initialize cache service for rescan\n",
    533       1.27    cegger 		    device_xname(&icp->icp_dv));
    534       1.10   thorpej 		return;
    535       1.10   thorpej 	}
    536       1.10   thorpej 	cdev_cnt = (u_int16_t) icp->icp_info;
    537       1.10   thorpej 
    538       1.10   thorpej 	/* For each host drive, do the new-style rescan. */
    539       1.10   thorpej 	for (unit = 0; unit < cdev_cnt && unit < ICP_MAX_HDRIVES; unit++)
    540       1.10   thorpej 		icp_rescan(icp, unit);
    541       1.10   thorpej 
    542       1.10   thorpej 	/* Now detach anything in the slots after cdev_cnt. */
    543       1.10   thorpej 	for (; unit < ICP_MAX_HDRIVES; unit++) {
    544       1.10   thorpej 		if (icp->icp_cdr[unit].cd_size != 0) {
    545       1.10   thorpej #ifdef ICP_DEBUG
    546       1.10   thorpej 			printf("%s: rescan all: unit %d < new cdev_cnt (%d)\n",
    547       1.27    cegger 			    device_xname(&icp->icp_dv), unit, cdev_cnt);
    548       1.10   thorpej #endif
    549       1.10   thorpej 			icp->icp_ndevs--;
    550       1.10   thorpej 			icp->icp_cdr[unit].cd_size = 0;
    551       1.10   thorpej 			if (icp->icp_children[unit] != NULL) {
    552       1.10   thorpej 				(void) config_detach(icp->icp_children[unit],
    553       1.10   thorpej 				    DETACH_FORCE);
    554       1.10   thorpej 				icp->icp_children[unit] = NULL;
    555       1.10   thorpej 			}
    556       1.10   thorpej 		}
    557       1.10   thorpej 	}
    558       1.10   thorpej 
    559       1.10   thorpej 	icp_recompute_openings(icp);
    560       1.10   thorpej }
    561       1.10   thorpej 
    562       1.10   thorpej void
    563       1.10   thorpej icp_recompute_openings(struct icp_softc *icp)
    564       1.10   thorpej {
    565       1.10   thorpej 	int unit, openings;
    566       1.10   thorpej 
    567       1.10   thorpej 	if (icp->icp_ndevs != 0)
    568       1.10   thorpej 		openings =
    569       1.10   thorpej 		    (icp->icp_nccbs - ICP_NCCB_RESERVE) / icp->icp_ndevs;
    570       1.10   thorpej 	else
    571       1.10   thorpej 		openings = 0;
    572       1.10   thorpej 	if (openings == icp->icp_openings)
    573       1.10   thorpej 		return;
    574       1.10   thorpej 	icp->icp_openings = openings;
    575       1.10   thorpej 
    576       1.10   thorpej #ifdef ICP_DEBUG
    577       1.10   thorpej 	printf("%s: %d device%s, %d openings per device\n",
    578       1.27    cegger 	    device_xname(&icp->icp_dv), icp->icp_ndevs,
    579       1.10   thorpej 	    icp->icp_ndevs == 1 ? "" : "s", icp->icp_openings);
    580       1.10   thorpej #endif
    581       1.10   thorpej 
    582       1.10   thorpej 	for (unit = 0; unit < ICP_MAX_HDRIVES + ICP_MAXBUS; unit++) {
    583       1.10   thorpej 		if (icp->icp_children[unit] != NULL)
    584       1.10   thorpej 			(*icp->icp_servicecb[unit]->iscb_openings)(
    585       1.10   thorpej 			    icp->icp_children[unit], icp->icp_openings);
    586       1.10   thorpej 	}
    587       1.10   thorpej }
    588       1.10   thorpej 
    589       1.10   thorpej void
    590        1.1        ad icp_watchdog(void *cookie)
    591        1.1        ad {
    592        1.1        ad 	struct icp_softc *icp;
    593        1.1        ad 	int s;
    594        1.1        ad 
    595        1.1        ad 	icp = cookie;
    596        1.1        ad 
    597        1.1        ad 	s = splbio();
    598        1.1        ad 	icp_intr(icp);
    599        1.8   thorpej 	if (ICP_HAS_WORK(icp))
    600        1.1        ad 		icp_ccb_enqueue(icp, NULL);
    601        1.1        ad 	splx(s);
    602        1.1        ad 
    603        1.1        ad 	callout_reset(&icp->icp_wdog_callout, hz * ICP_WATCHDOG_FREQ,
    604        1.1        ad 	    icp_watchdog, icp);
    605        1.1        ad }
    606        1.1        ad 
    607        1.1        ad int
    608        1.1        ad icp_print(void *aux, const char *pnp)
    609        1.1        ad {
    610        1.1        ad 	struct icp_attach_args *icpa;
    611        1.1        ad 	const char *str;
    612        1.1        ad 
    613        1.1        ad 	icpa = (struct icp_attach_args *)aux;
    614        1.1        ad 
    615        1.1        ad 	if (pnp != NULL) {
    616        1.1        ad 		if (icpa->icpa_unit < ICPA_UNIT_SCSI)
    617        1.1        ad 			str = "block device";
    618        1.1        ad 		else
    619        1.1        ad 			str = "SCSI channel";
    620        1.6   thorpej 		aprint_normal("%s at %s", str, pnp);
    621        1.1        ad 	}
    622        1.6   thorpej 	aprint_normal(" unit %d", icpa->icpa_unit);
    623        1.1        ad 
    624        1.1        ad 	return (UNCONF);
    625        1.1        ad }
    626        1.1        ad 
    627        1.1        ad int
    628        1.8   thorpej icp_async_event(struct icp_softc *icp, int service)
    629        1.1        ad {
    630        1.1        ad 
    631        1.8   thorpej 	if (service == ICP_SCREENSERVICE) {
    632        1.8   thorpej 		if (icp->icp_status == ICP_S_MSG_REQUEST) {
    633        1.8   thorpej 			/* XXX */
    634        1.8   thorpej 		}
    635        1.8   thorpej 	} else {
    636        1.8   thorpej 		if ((icp->icp_fw_vers & 0xff) >= 0x1a) {
    637        1.8   thorpej 			icp->icp_evt.size = 0;
    638       1.19   thorpej 			icp->icp_evt.eu.async.ionode =
    639       1.19   thorpej 			    device_unit(&icp->icp_dv);
    640        1.8   thorpej 			icp->icp_evt.eu.async.status = icp->icp_status;
    641        1.8   thorpej 			/*
    642        1.8   thorpej 			 * Severity and event string are filled in by the
    643        1.8   thorpej 			 * hardware interface interrupt handler.
    644        1.8   thorpej 			 */
    645       1.27    cegger 			printf("%s: %s\n", device_xname(&icp->icp_dv),
    646        1.8   thorpej 			    icp->icp_evt.event_string);
    647        1.8   thorpej 		} else {
    648        1.8   thorpej 			icp->icp_evt.size = sizeof(icp->icp_evt.eu.async);
    649       1.19   thorpej 			icp->icp_evt.eu.async.ionode =
    650       1.19   thorpej 			    device_unit(&icp->icp_dv);
    651        1.8   thorpej 			icp->icp_evt.eu.async.service = service;
    652        1.8   thorpej 			icp->icp_evt.eu.async.status = icp->icp_status;
    653        1.8   thorpej 			icp->icp_evt.eu.async.info = icp->icp_info;
    654        1.8   thorpej 			/* XXXJRT FIX THIS */
    655       1.14     perry 			*(u_int32_t *) icp->icp_evt.eu.async.scsi_coord =
    656        1.8   thorpej 			    icp->icp_info2;
    657        1.8   thorpej 		}
    658        1.8   thorpej 		icp_store_event(icp, GDT_ES_ASYNC, service, &icp->icp_evt);
    659        1.8   thorpej 	}
    660        1.8   thorpej 
    661        1.8   thorpej 	return (0);
    662        1.1        ad }
    663        1.1        ad 
    664        1.1        ad int
    665        1.1        ad icp_intr(void *cookie)
    666        1.1        ad {
    667        1.1        ad 	struct icp_softc *icp;
    668        1.1        ad 	struct icp_intr_ctx ctx;
    669        1.1        ad 	struct icp_ccb *ic;
    670        1.1        ad 
    671        1.1        ad 	icp = cookie;
    672        1.1        ad 
    673        1.1        ad 	ctx.istatus = (*icp->icp_get_status)(icp);
    674        1.1        ad 	if (!ctx.istatus) {
    675        1.1        ad 		icp->icp_status = ICP_S_NO_STATUS;
    676        1.1        ad 		return (0);
    677        1.1        ad 	}
    678        1.1        ad 
    679        1.1        ad 	(*icp->icp_intr)(icp, &ctx);
    680        1.1        ad 
    681        1.1        ad 	icp->icp_status = ctx.cmd_status;
    682        1.8   thorpej 	icp->icp_service = ctx.service;
    683        1.1        ad 	icp->icp_info = ctx.info;
    684        1.1        ad 	icp->icp_info2 = ctx.info2;
    685        1.1        ad 
    686        1.1        ad 	switch (ctx.istatus) {
    687        1.1        ad 	case ICP_ASYNCINDEX:
    688        1.1        ad 		icp_async_event(icp, ctx.service);
    689        1.1        ad 		return (1);
    690        1.1        ad 
    691        1.1        ad 	case ICP_SPEZINDEX:
    692       1.27    cegger 		aprint_error_dev(&icp->icp_dv, "uninitialized or unknown service (%d/%d)\n",
    693       1.27    cegger 		    ctx.info, ctx.info2);
    694        1.8   thorpej 		icp->icp_evt.size = sizeof(icp->icp_evt.eu.driver);
    695       1.19   thorpej 		icp->icp_evt.eu.driver.ionode = device_unit(&icp->icp_dv);
    696        1.8   thorpej 		icp_store_event(icp, GDT_ES_DRIVER, 4, &icp->icp_evt);
    697        1.1        ad 		return (1);
    698        1.1        ad 	}
    699        1.1        ad 
    700        1.1        ad 	if ((ctx.istatus - 2) > icp->icp_nccbs)
    701        1.1        ad 		panic("icp_intr: bad command index returned");
    702        1.1        ad 
    703        1.1        ad 	ic = &icp->icp_ccbs[ctx.istatus - 2];
    704        1.1        ad 	ic->ic_status = icp->icp_status;
    705        1.1        ad 
    706        1.8   thorpej 	if ((ic->ic_flags & IC_ALLOCED) == 0) {
    707        1.8   thorpej 		/* XXX ICP's "iir" driver just sends an event here. */
    708        1.1        ad 		panic("icp_intr: inactive CCB identified");
    709        1.8   thorpej 	}
    710        1.1        ad 
    711       1.10   thorpej 	/*
    712       1.10   thorpej 	 * Try to protect ourselves from the running command count already
    713       1.10   thorpej 	 * being 0 (e.g. if a polled command times out).
    714       1.10   thorpej 	 */
    715       1.10   thorpej 	KDASSERT(icp->icp_running != 0);
    716       1.10   thorpej 	if (--icp->icp_running == 0 &&
    717       1.10   thorpej 	    (icp->icp_flags & ICP_F_WAIT_FREEZE) != 0) {
    718       1.10   thorpej 		icp->icp_flags &= ~ICP_F_WAIT_FREEZE;
    719       1.10   thorpej 		wakeup(&icp->icp_qfreeze);
    720       1.10   thorpej 	}
    721       1.10   thorpej 
    722        1.1        ad 	switch (icp->icp_status) {
    723        1.1        ad 	case ICP_S_BSY:
    724        1.1        ad #ifdef ICP_DEBUG
    725       1.27    cegger 		printf("%s: ICP_S_BSY received\n", device_xname(&icp->icp_dv));
    726        1.1        ad #endif
    727        1.8   thorpej 		if (__predict_false((ic->ic_flags & IC_UCMD) != 0))
    728        1.8   thorpej 			SIMPLEQ_INSERT_HEAD(&icp->icp_ucmd_queue, ic, ic_chain);
    729        1.8   thorpej 		else
    730        1.8   thorpej 			SIMPLEQ_INSERT_HEAD(&icp->icp_ccb_queue, ic, ic_chain);
    731        1.1        ad 		break;
    732        1.1        ad 
    733        1.1        ad 	default:
    734        1.1        ad 		ic->ic_flags |= IC_COMPLETE;
    735        1.1        ad 
    736        1.1        ad 		if ((ic->ic_flags & IC_WAITING) != 0)
    737        1.1        ad 			wakeup(ic);
    738        1.1        ad 		else if (ic->ic_intr != NULL)
    739        1.1        ad 			(*ic->ic_intr)(ic);
    740        1.1        ad 
    741        1.8   thorpej 		if (ICP_HAS_WORK(icp))
    742        1.1        ad 			icp_ccb_enqueue(icp, NULL);
    743        1.1        ad 
    744        1.1        ad 		break;
    745        1.1        ad 	}
    746        1.1        ad 
    747        1.1        ad 	return (1);
    748        1.1        ad }
    749        1.1        ad 
    750        1.8   thorpej struct icp_ucmd_ctx {
    751        1.8   thorpej 	gdt_ucmd_t *iu_ucmd;
    752        1.8   thorpej 	u_int32_t iu_cnt;
    753        1.8   thorpej };
    754        1.8   thorpej 
    755        1.8   thorpej void
    756        1.8   thorpej icp_ucmd_intr(struct icp_ccb *ic)
    757        1.8   thorpej {
    758        1.8   thorpej 	struct icp_softc *icp = (void *) ic->ic_dv;
    759        1.8   thorpej 	struct icp_ucmd_ctx *iu = ic->ic_context;
    760        1.8   thorpej 	gdt_ucmd_t *ucmd = iu->iu_ucmd;
    761        1.8   thorpej 
    762        1.8   thorpej 	ucmd->status = icp->icp_status;
    763        1.8   thorpej 	ucmd->info = icp->icp_info;
    764        1.8   thorpej 
    765        1.8   thorpej 	if (iu->iu_cnt != 0) {
    766        1.8   thorpej 		bus_dmamap_sync(icp->icp_dmat,
    767        1.8   thorpej 		    icp->icp_scr_dmamap,
    768        1.8   thorpej 		    ICP_SCRATCH_UCMD, iu->iu_cnt,
    769        1.8   thorpej 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
    770        1.8   thorpej 		memcpy(ucmd->data,
    771       1.23  christos 		    (char *)icp->icp_scr + ICP_SCRATCH_UCMD, iu->iu_cnt);
    772        1.8   thorpej 	}
    773        1.8   thorpej 
    774        1.8   thorpej 	icp->icp_ucmd_ccb = NULL;
    775        1.8   thorpej 
    776        1.8   thorpej 	ic->ic_flags |= IC_COMPLETE;
    777        1.8   thorpej 	wakeup(ic);
    778        1.8   thorpej }
    779        1.8   thorpej 
    780        1.8   thorpej /*
    781        1.8   thorpej  * NOTE: We assume that it is safe to sleep here!
    782        1.8   thorpej  */
    783        1.1        ad int
    784        1.1        ad icp_cmd(struct icp_softc *icp, u_int8_t service, u_int16_t opcode,
    785        1.1        ad 	u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
    786        1.1        ad {
    787        1.1        ad 	struct icp_ioctlcmd *icmd;
    788        1.1        ad 	struct icp_cachecmd *cc;
    789        1.1        ad 	struct icp_rawcmd *rc;
    790        1.1        ad 	int retries, rv;
    791        1.1        ad 	struct icp_ccb *ic;
    792        1.1        ad 
    793        1.1        ad 	retries = ICP_RETRIES;
    794        1.1        ad 
    795        1.1        ad 	do {
    796        1.8   thorpej 		ic = icp_ccb_alloc_wait(icp);
    797        1.1        ad 		memset(&ic->ic_cmd, 0, sizeof(ic->ic_cmd));
    798        1.1        ad 		ic->ic_cmd.cmd_opcode = htole16(opcode);
    799        1.1        ad 
    800        1.1        ad 		switch (service) {
    801        1.1        ad 		case ICP_CACHESERVICE:
    802        1.1        ad 			if (opcode == ICP_IOCTL) {
    803        1.1        ad 				icmd = &ic->ic_cmd.cmd_packet.ic;
    804        1.1        ad 				icmd->ic_subfunc = htole16(arg1);
    805        1.1        ad 				icmd->ic_channel = htole32(arg2);
    806        1.1        ad 				icmd->ic_bufsize = htole32(arg3);
    807        1.1        ad 				icmd->ic_addr =
    808        1.1        ad 				    htole32(icp->icp_scr_seg[0].ds_addr);
    809        1.1        ad 
    810        1.1        ad 				bus_dmamap_sync(icp->icp_dmat,
    811        1.1        ad 				    icp->icp_scr_dmamap, 0, arg3,
    812        1.1        ad 				    BUS_DMASYNC_PREWRITE |
    813        1.1        ad 				    BUS_DMASYNC_PREREAD);
    814        1.1        ad 			} else {
    815        1.1        ad 				cc = &ic->ic_cmd.cmd_packet.cc;
    816        1.1        ad 				cc->cc_deviceno = htole16(arg1);
    817        1.1        ad 				cc->cc_blockno = htole32(arg2);
    818        1.1        ad 			}
    819        1.1        ad 			break;
    820        1.1        ad 
    821        1.1        ad 		case ICP_SCSIRAWSERVICE:
    822        1.1        ad 			rc = &ic->ic_cmd.cmd_packet.rc;
    823        1.1        ad 			rc->rc_direction = htole32(arg1);
    824        1.1        ad 			rc->rc_bus = arg2;
    825        1.1        ad 			rc->rc_target = arg3;
    826        1.1        ad 			rc->rc_lun = arg3 >> 8;
    827        1.1        ad 			break;
    828        1.1        ad 		}
    829        1.1        ad 
    830        1.1        ad 		ic->ic_service = service;
    831        1.1        ad 		ic->ic_cmdlen = sizeof(ic->ic_cmd);
    832        1.1        ad 		rv = icp_ccb_poll(icp, ic, 10000);
    833        1.1        ad 
    834        1.1        ad 		switch (service) {
    835        1.1        ad 		case ICP_CACHESERVICE:
    836        1.1        ad 			if (opcode == ICP_IOCTL) {
    837        1.1        ad 				bus_dmamap_sync(icp->icp_dmat,
    838        1.1        ad 				    icp->icp_scr_dmamap, 0, arg3,
    839        1.1        ad 				    BUS_DMASYNC_POSTWRITE |
    840        1.1        ad 				    BUS_DMASYNC_POSTREAD);
    841        1.1        ad 			}
    842        1.1        ad 			break;
    843        1.1        ad 		}
    844        1.1        ad 
    845        1.1        ad 		icp_ccb_free(icp, ic);
    846        1.1        ad 	} while (rv != 0 && --retries > 0);
    847        1.1        ad 
    848        1.1        ad 	return (icp->icp_status == ICP_S_OK);
    849        1.1        ad }
    850        1.1        ad 
    851        1.8   thorpej int
    852        1.8   thorpej icp_ucmd(struct icp_softc *icp, gdt_ucmd_t *ucmd)
    853        1.8   thorpej {
    854        1.8   thorpej 	struct icp_ccb *ic;
    855        1.8   thorpej 	struct icp_ucmd_ctx iu;
    856        1.8   thorpej 	u_int32_t cnt;
    857        1.8   thorpej 	int error;
    858        1.8   thorpej 
    859        1.8   thorpej 	if (ucmd->service == ICP_CACHESERVICE) {
    860        1.8   thorpej 		if (ucmd->command.cmd_opcode == ICP_IOCTL) {
    861        1.8   thorpej 			cnt = ucmd->command.cmd_packet.ic.ic_bufsize;
    862        1.8   thorpej 			if (cnt > GDT_SCRATCH_SZ) {
    863       1.27    cegger 				aprint_error_dev(&icp->icp_dv, "scratch buffer too small (%d/%d)\n",
    864       1.27    cegger 				    GDT_SCRATCH_SZ, cnt);
    865        1.8   thorpej 				return (EINVAL);
    866        1.8   thorpej 			}
    867        1.8   thorpej 		} else {
    868        1.8   thorpej 			cnt = ucmd->command.cmd_packet.cc.cc_blockcnt *
    869        1.8   thorpej 			    ICP_SECTOR_SIZE;
    870        1.8   thorpej 			if (cnt > GDT_SCRATCH_SZ) {
    871       1.27    cegger 				aprint_error_dev(&icp->icp_dv, "scratch buffer too small (%d/%d)\n",
    872       1.27    cegger 				    GDT_SCRATCH_SZ, cnt);
    873        1.8   thorpej 				return (EINVAL);
    874        1.8   thorpej 			}
    875        1.8   thorpej 		}
    876        1.8   thorpej 	} else {
    877        1.8   thorpej 		cnt = ucmd->command.cmd_packet.rc.rc_sdlen +
    878        1.8   thorpej 		    ucmd->command.cmd_packet.rc.rc_sense_len;
    879        1.8   thorpej 		if (cnt > GDT_SCRATCH_SZ) {
    880       1.27    cegger 			aprint_error_dev(&icp->icp_dv, "scratch buffer too small (%d/%d)\n",
    881       1.27    cegger 			    GDT_SCRATCH_SZ, cnt);
    882        1.8   thorpej 			return (EINVAL);
    883        1.8   thorpej 		}
    884        1.8   thorpej 	}
    885        1.8   thorpej 
    886        1.8   thorpej 	iu.iu_ucmd = ucmd;
    887        1.8   thorpej 	iu.iu_cnt = cnt;
    888        1.8   thorpej 
    889        1.8   thorpej 	ic = icp_ccb_alloc_wait(icp);
    890        1.8   thorpej 	memset(&ic->ic_cmd, 0, sizeof(ic->ic_cmd));
    891        1.8   thorpej 	ic->ic_cmd.cmd_opcode = htole16(ucmd->command.cmd_opcode);
    892        1.8   thorpej 
    893        1.8   thorpej 	if (ucmd->service == ICP_CACHESERVICE) {
    894        1.8   thorpej 		if (ucmd->command.cmd_opcode == ICP_IOCTL) {
    895        1.8   thorpej 			struct icp_ioctlcmd *icmd, *uicmd;
    896        1.8   thorpej 
    897        1.8   thorpej 			icmd = &ic->ic_cmd.cmd_packet.ic;
    898        1.8   thorpej 			uicmd = &ucmd->command.cmd_packet.ic;
    899        1.8   thorpej 
    900        1.8   thorpej 			icmd->ic_subfunc = htole16(uicmd->ic_subfunc);
    901        1.8   thorpej 			icmd->ic_channel = htole32(uicmd->ic_channel);
    902        1.8   thorpej 			icmd->ic_bufsize = htole32(uicmd->ic_bufsize);
    903        1.8   thorpej 			icmd->ic_addr =
    904        1.8   thorpej 			    htole32(icp->icp_scr_seg[0].ds_addr +
    905        1.8   thorpej 				    ICP_SCRATCH_UCMD);
    906        1.8   thorpej 		} else {
    907        1.8   thorpej 			struct icp_cachecmd *cc, *ucc;
    908        1.8   thorpej 
    909        1.8   thorpej 			cc = &ic->ic_cmd.cmd_packet.cc;
    910        1.8   thorpej 			ucc = &ucmd->command.cmd_packet.cc;
    911        1.8   thorpej 
    912        1.8   thorpej 			cc->cc_deviceno = htole16(ucc->cc_deviceno);
    913        1.8   thorpej 			cc->cc_blockno = htole32(ucc->cc_blockno);
    914        1.8   thorpej 			cc->cc_blockcnt = htole32(ucc->cc_blockcnt);
    915        1.8   thorpej 			cc->cc_addr = htole32(0xffffffffU);
    916        1.8   thorpej 			cc->cc_nsgent = htole32(1);
    917        1.8   thorpej 			cc->cc_sg[0].sg_addr =
    918        1.8   thorpej 			    htole32(icp->icp_scr_seg[0].ds_addr +
    919        1.8   thorpej 				    ICP_SCRATCH_UCMD);
    920        1.8   thorpej 			cc->cc_sg[0].sg_len = htole32(cnt);
    921        1.8   thorpej 		}
    922        1.8   thorpej 	} else {
    923        1.8   thorpej 		struct icp_rawcmd *rc, *urc;
    924        1.8   thorpej 
    925        1.8   thorpej 		rc = &ic->ic_cmd.cmd_packet.rc;
    926        1.8   thorpej 		urc = &ucmd->command.cmd_packet.rc;
    927        1.8   thorpej 
    928        1.8   thorpej 		rc->rc_direction = htole32(urc->rc_direction);
    929        1.8   thorpej 		rc->rc_sdata = htole32(0xffffffffU);
    930        1.8   thorpej 		rc->rc_sdlen = htole32(urc->rc_sdlen);
    931        1.8   thorpej 		rc->rc_clen = htole32(urc->rc_clen);
    932        1.8   thorpej 		memcpy(rc->rc_cdb, urc->rc_cdb, sizeof(rc->rc_cdb));
    933        1.8   thorpej 		rc->rc_target = urc->rc_target;
    934        1.8   thorpej 		rc->rc_lun = urc->rc_lun;
    935        1.8   thorpej 		rc->rc_bus = urc->rc_bus;
    936        1.8   thorpej 		rc->rc_sense_len = htole32(urc->rc_sense_len);
    937        1.8   thorpej 		rc->rc_sense_addr =
    938        1.8   thorpej 		    htole32(icp->icp_scr_seg[0].ds_addr +
    939        1.8   thorpej 			    ICP_SCRATCH_UCMD + urc->rc_sdlen);
    940        1.8   thorpej 		rc->rc_nsgent = htole32(1);
    941        1.8   thorpej 		rc->rc_sg[0].sg_addr =
    942        1.8   thorpej 		    htole32(icp->icp_scr_seg[0].ds_addr + ICP_SCRATCH_UCMD);
    943        1.8   thorpej 		rc->rc_sg[0].sg_len = htole32(cnt - urc->rc_sense_len);
    944        1.8   thorpej 	}
    945        1.8   thorpej 
    946        1.8   thorpej 	ic->ic_service = ucmd->service;
    947        1.8   thorpej 	ic->ic_cmdlen = sizeof(ic->ic_cmd);
    948        1.8   thorpej 	ic->ic_context = &iu;
    949        1.8   thorpej 
    950        1.8   thorpej 	/*
    951        1.8   thorpej 	 * XXX What units are ucmd->timeout in?  Until we know, we
    952        1.8   thorpej 	 * XXX just pull a number out of thin air.
    953        1.8   thorpej 	 */
    954        1.8   thorpej 	if (__predict_false((error = icp_ccb_wait_user(icp, ic, 30000)) != 0))
    955       1.27    cegger 		aprint_error_dev(&icp->icp_dv, "error %d waiting for ucmd to complete\n",
    956       1.27    cegger 		    error);
    957        1.8   thorpej 
    958        1.8   thorpej 	/* icp_ucmd_intr() has updated ucmd. */
    959        1.8   thorpej 	icp_ccb_free(icp, ic);
    960        1.8   thorpej 
    961        1.8   thorpej 	return (error);
    962        1.8   thorpej }
    963        1.8   thorpej 
    964        1.1        ad struct icp_ccb *
    965        1.1        ad icp_ccb_alloc(struct icp_softc *icp)
    966        1.1        ad {
    967        1.1        ad 	struct icp_ccb *ic;
    968        1.1        ad 	int s;
    969        1.1        ad 
    970        1.1        ad 	s = splbio();
    971        1.8   thorpej 	if (__predict_false((ic =
    972        1.8   thorpej 			     SIMPLEQ_FIRST(&icp->icp_ccb_freelist)) == NULL)) {
    973        1.8   thorpej 		splx(s);
    974        1.8   thorpej 		return (NULL);
    975        1.8   thorpej 	}
    976        1.8   thorpej 	SIMPLEQ_REMOVE_HEAD(&icp->icp_ccb_freelist, ic_chain);
    977        1.8   thorpej 	splx(s);
    978        1.8   thorpej 
    979        1.8   thorpej 	ic->ic_flags = IC_ALLOCED;
    980        1.8   thorpej 	return (ic);
    981        1.8   thorpej }
    982        1.8   thorpej 
    983        1.8   thorpej struct icp_ccb *
    984        1.8   thorpej icp_ccb_alloc_wait(struct icp_softc *icp)
    985        1.8   thorpej {
    986        1.8   thorpej 	struct icp_ccb *ic;
    987        1.8   thorpej 	int s;
    988        1.8   thorpej 
    989        1.8   thorpej 	s = splbio();
    990        1.8   thorpej 	while ((ic = SIMPLEQ_FIRST(&icp->icp_ccb_freelist)) == NULL) {
    991        1.8   thorpej 		icp->icp_flags |= ICP_F_WAIT_CCB;
    992        1.8   thorpej 		(void) tsleep(&icp->icp_ccb_freelist, PRIBIO, "icpccb", 0);
    993        1.8   thorpej 	}
    994        1.2     lukem 	SIMPLEQ_REMOVE_HEAD(&icp->icp_ccb_freelist, ic_chain);
    995        1.1        ad 	splx(s);
    996        1.1        ad 
    997        1.1        ad 	ic->ic_flags = IC_ALLOCED;
    998        1.1        ad 	return (ic);
    999        1.1        ad }
   1000        1.1        ad 
   1001        1.1        ad void
   1002        1.1        ad icp_ccb_free(struct icp_softc *icp, struct icp_ccb *ic)
   1003        1.1        ad {
   1004        1.1        ad 	int s;
   1005        1.1        ad 
   1006        1.1        ad 	s = splbio();
   1007        1.1        ad 	ic->ic_flags = 0;
   1008        1.1        ad 	ic->ic_intr = NULL;
   1009        1.1        ad 	SIMPLEQ_INSERT_HEAD(&icp->icp_ccb_freelist, ic, ic_chain);
   1010        1.8   thorpej 	if (__predict_false((icp->icp_flags & ICP_F_WAIT_CCB) != 0)) {
   1011        1.8   thorpej 		icp->icp_flags &= ~ICP_F_WAIT_CCB;
   1012        1.8   thorpej 		wakeup(&icp->icp_ccb_freelist);
   1013        1.8   thorpej 	}
   1014        1.1        ad 	splx(s);
   1015        1.1        ad }
   1016        1.1        ad 
   1017        1.1        ad void
   1018        1.1        ad icp_ccb_enqueue(struct icp_softc *icp, struct icp_ccb *ic)
   1019        1.1        ad {
   1020        1.1        ad 	int s;
   1021        1.1        ad 
   1022        1.1        ad 	s = splbio();
   1023        1.1        ad 
   1024        1.8   thorpej 	if (ic != NULL) {
   1025        1.8   thorpej 		if (__predict_false((ic->ic_flags & IC_UCMD) != 0))
   1026        1.8   thorpej 			SIMPLEQ_INSERT_TAIL(&icp->icp_ucmd_queue, ic, ic_chain);
   1027        1.8   thorpej 		else
   1028        1.8   thorpej 			SIMPLEQ_INSERT_TAIL(&icp->icp_ccb_queue, ic, ic_chain);
   1029        1.8   thorpej 	}
   1030        1.8   thorpej 
   1031       1.10   thorpej 	for (; icp->icp_qfreeze == 0;) {
   1032        1.8   thorpej 		if (__predict_false((ic =
   1033        1.8   thorpej 			    SIMPLEQ_FIRST(&icp->icp_ucmd_queue)) != NULL)) {
   1034        1.8   thorpej 			struct icp_ucmd_ctx *iu = ic->ic_context;
   1035        1.8   thorpej 			gdt_ucmd_t *ucmd = iu->iu_ucmd;
   1036        1.1        ad 
   1037        1.8   thorpej 			/*
   1038        1.8   thorpej 			 * All user-generated commands share the same
   1039        1.8   thorpej 			 * scratch space, so if one is already running,
   1040        1.8   thorpej 			 * we have to stall the command queue.
   1041        1.8   thorpej 			 */
   1042        1.8   thorpej 			if (icp->icp_ucmd_ccb != NULL)
   1043        1.8   thorpej 				break;
   1044        1.9   thorpej 			if ((*icp->icp_test_busy)(icp))
   1045        1.9   thorpej 				break;
   1046        1.8   thorpej 			icp->icp_ucmd_ccb = ic;
   1047        1.8   thorpej 
   1048        1.8   thorpej 			if (iu->iu_cnt != 0) {
   1049       1.23  christos 				memcpy((char *)icp->icp_scr + ICP_SCRATCH_UCMD,
   1050        1.8   thorpej 				    ucmd->data, iu->iu_cnt);
   1051        1.8   thorpej 				bus_dmamap_sync(icp->icp_dmat,
   1052        1.8   thorpej 				    icp->icp_scr_dmamap,
   1053        1.8   thorpej 				    ICP_SCRATCH_UCMD, iu->iu_cnt,
   1054        1.8   thorpej 				    BUS_DMASYNC_PREREAD |
   1055        1.8   thorpej 				    BUS_DMASYNC_PREWRITE);
   1056        1.8   thorpej 			}
   1057        1.9   thorpej 		} else if (__predict_true((ic =
   1058        1.9   thorpej 				SIMPLEQ_FIRST(&icp->icp_ccb_queue)) != NULL)) {
   1059        1.9   thorpej 			if ((*icp->icp_test_busy)(icp))
   1060        1.9   thorpej 				break;
   1061        1.9   thorpej 		} else {
   1062        1.9   thorpej 			/* no command found */
   1063        1.1        ad 			break;
   1064        1.9   thorpej 		}
   1065        1.1        ad 		icp_ccb_submit(icp, ic);
   1066        1.8   thorpej 		if (__predict_false((ic->ic_flags & IC_UCMD) != 0))
   1067        1.8   thorpej 			SIMPLEQ_REMOVE_HEAD(&icp->icp_ucmd_queue, ic_chain);
   1068        1.8   thorpej 		else
   1069        1.8   thorpej 			SIMPLEQ_REMOVE_HEAD(&icp->icp_ccb_queue, ic_chain);
   1070        1.1        ad 	}
   1071        1.1        ad 
   1072        1.1        ad 	splx(s);
   1073        1.1        ad }
   1074        1.1        ad 
   1075        1.1        ad int
   1076        1.1        ad icp_ccb_map(struct icp_softc *icp, struct icp_ccb *ic, void *data, int size,
   1077        1.1        ad 	    int dir)
   1078        1.1        ad {
   1079        1.1        ad 	struct icp_sg *sg;
   1080        1.1        ad 	int nsegs, i, rv;
   1081        1.1        ad 	bus_dmamap_t xfer;
   1082        1.1        ad 
   1083        1.1        ad 	xfer = ic->ic_xfer_map;
   1084        1.1        ad 
   1085        1.1        ad 	rv = bus_dmamap_load(icp->icp_dmat, xfer, data, size, NULL,
   1086        1.1        ad 	    BUS_DMA_NOWAIT | BUS_DMA_STREAMING |
   1087        1.1        ad 	    ((dir & IC_XFER_IN) ? BUS_DMA_READ : BUS_DMA_WRITE));
   1088        1.1        ad 	if (rv != 0)
   1089        1.1        ad 		return (rv);
   1090        1.1        ad 
   1091        1.1        ad 	nsegs = xfer->dm_nsegs;
   1092        1.1        ad 	ic->ic_xfer_size = size;
   1093        1.1        ad 	ic->ic_nsgent = nsegs;
   1094        1.1        ad 	ic->ic_flags |= dir;
   1095        1.1        ad 	sg = ic->ic_sg;
   1096        1.1        ad 
   1097        1.1        ad 	if (sg != NULL) {
   1098        1.1        ad 		for (i = 0; i < nsegs; i++, sg++) {
   1099        1.1        ad 			sg->sg_addr = htole32(xfer->dm_segs[i].ds_addr);
   1100        1.1        ad 			sg->sg_len = htole32(xfer->dm_segs[i].ds_len);
   1101        1.1        ad 		}
   1102        1.1        ad 	} else if (nsegs > 1)
   1103        1.4    provos 		panic("icp_ccb_map: no SG list specified, but nsegs > 1");
   1104        1.1        ad 
   1105        1.1        ad 	if ((dir & IC_XFER_OUT) != 0)
   1106        1.1        ad 		i = BUS_DMASYNC_PREWRITE;
   1107        1.1        ad 	else /* if ((dir & IC_XFER_IN) != 0) */
   1108        1.1        ad 		i = BUS_DMASYNC_PREREAD;
   1109        1.1        ad 
   1110        1.1        ad 	bus_dmamap_sync(icp->icp_dmat, xfer, 0, ic->ic_xfer_size, i);
   1111        1.1        ad 	return (0);
   1112        1.1        ad }
   1113        1.1        ad 
   1114        1.1        ad void
   1115        1.1        ad icp_ccb_unmap(struct icp_softc *icp, struct icp_ccb *ic)
   1116        1.1        ad {
   1117        1.1        ad 	int i;
   1118        1.1        ad 
   1119        1.1        ad 	if ((ic->ic_flags & IC_XFER_OUT) != 0)
   1120        1.1        ad 		i = BUS_DMASYNC_POSTWRITE;
   1121        1.1        ad 	else /* if ((ic->ic_flags & IC_XFER_IN) != 0) */
   1122        1.1        ad 		i = BUS_DMASYNC_POSTREAD;
   1123        1.1        ad 
   1124        1.1        ad 	bus_dmamap_sync(icp->icp_dmat, ic->ic_xfer_map, 0, ic->ic_xfer_size, i);
   1125        1.1        ad 	bus_dmamap_unload(icp->icp_dmat, ic->ic_xfer_map);
   1126        1.1        ad }
   1127        1.1        ad 
   1128        1.1        ad int
   1129        1.1        ad icp_ccb_poll(struct icp_softc *icp, struct icp_ccb *ic, int timo)
   1130        1.1        ad {
   1131       1.10   thorpej 	int s, rv;
   1132       1.10   thorpej 
   1133       1.10   thorpej 	s = splbio();
   1134        1.1        ad 
   1135        1.1        ad 	for (timo = ICP_BUSY_WAIT_MS * 100; timo != 0; timo--) {
   1136        1.1        ad 		if (!(*icp->icp_test_busy)(icp))
   1137        1.1        ad 			break;
   1138        1.1        ad 		DELAY(10);
   1139        1.1        ad 	}
   1140        1.1        ad 	if (timo == 0) {
   1141       1.27    cegger 		printf("%s: submit: busy\n", device_xname(&icp->icp_dv));
   1142        1.1        ad 		return (EAGAIN);
   1143        1.1        ad 	}
   1144        1.1        ad 
   1145        1.1        ad 	icp_ccb_submit(icp, ic);
   1146        1.1        ad 
   1147       1.10   thorpej 	if (cold) {
   1148       1.10   thorpej 		for (timo *= 10; timo != 0; timo--) {
   1149       1.10   thorpej 			DELAY(100);
   1150       1.10   thorpej 			icp_intr(icp);
   1151       1.10   thorpej 			if ((ic->ic_flags & IC_COMPLETE) != 0)
   1152       1.10   thorpej 				break;
   1153       1.10   thorpej 		}
   1154       1.10   thorpej 	} else {
   1155       1.10   thorpej 		ic->ic_flags |= IC_WAITING;
   1156       1.10   thorpej 		while ((ic->ic_flags & IC_COMPLETE) == 0) {
   1157       1.10   thorpej 			if ((rv = tsleep(ic, PRIBIO, "icpwccb",
   1158       1.10   thorpej 					 mstohz(timo))) != 0) {
   1159       1.10   thorpej 				timo = 0;
   1160       1.10   thorpej 				break;
   1161       1.10   thorpej 			}
   1162       1.10   thorpej 		}
   1163        1.1        ad 	}
   1164        1.1        ad 
   1165        1.1        ad 	if (timo != 0) {
   1166        1.1        ad 		if (ic->ic_status != ICP_S_OK) {
   1167        1.1        ad #ifdef ICP_DEBUG
   1168        1.1        ad 			printf("%s: request failed; status=0x%04x\n",
   1169       1.27    cegger 			    device_xname(&icp->icp_dv), ic->ic_status);
   1170        1.1        ad #endif
   1171        1.1        ad 			rv = EIO;
   1172        1.1        ad 		} else
   1173        1.1        ad 			rv = 0;
   1174        1.1        ad 	} else {
   1175       1.27    cegger 		aprint_error_dev(&icp->icp_dv, "command timed out\n");
   1176        1.1        ad 		rv = EIO;
   1177        1.1        ad 	}
   1178        1.1        ad 
   1179        1.1        ad 	while ((*icp->icp_test_busy)(icp) != 0)
   1180        1.1        ad 		DELAY(10);
   1181        1.1        ad 
   1182       1.10   thorpej 	splx(s);
   1183       1.10   thorpej 
   1184        1.1        ad 	return (rv);
   1185        1.1        ad }
   1186        1.1        ad 
   1187        1.1        ad int
   1188        1.1        ad icp_ccb_wait(struct icp_softc *icp, struct icp_ccb *ic, int timo)
   1189        1.1        ad {
   1190        1.1        ad 	int s, rv;
   1191        1.1        ad 
   1192        1.1        ad 	ic->ic_flags |= IC_WAITING;
   1193        1.1        ad 
   1194        1.1        ad 	s = splbio();
   1195        1.1        ad 	icp_ccb_enqueue(icp, ic);
   1196        1.8   thorpej 	while ((ic->ic_flags & IC_COMPLETE) == 0) {
   1197        1.8   thorpej 		if ((rv = tsleep(ic, PRIBIO, "icpwccb", mstohz(timo))) != 0) {
   1198        1.8   thorpej 			splx(s);
   1199        1.8   thorpej 			return (rv);
   1200        1.8   thorpej 		}
   1201        1.1        ad 	}
   1202        1.1        ad 	splx(s);
   1203        1.1        ad 
   1204        1.1        ad 	if (ic->ic_status != ICP_S_OK) {
   1205       1.27    cegger 		aprint_error_dev(&icp->icp_dv, "command failed; status=%x\n",
   1206        1.1        ad 		    ic->ic_status);
   1207        1.1        ad 		return (EIO);
   1208        1.1        ad 	}
   1209        1.1        ad 
   1210        1.1        ad 	return (0);
   1211        1.1        ad }
   1212        1.1        ad 
   1213        1.8   thorpej int
   1214        1.8   thorpej icp_ccb_wait_user(struct icp_softc *icp, struct icp_ccb *ic, int timo)
   1215        1.8   thorpej {
   1216        1.8   thorpej 	int s, rv;
   1217        1.8   thorpej 
   1218        1.8   thorpej 	ic->ic_dv = &icp->icp_dv;
   1219        1.8   thorpej 	ic->ic_intr = icp_ucmd_intr;
   1220        1.8   thorpej 	ic->ic_flags |= IC_UCMD;
   1221        1.8   thorpej 
   1222        1.8   thorpej 	s = splbio();
   1223        1.8   thorpej 	icp_ccb_enqueue(icp, ic);
   1224        1.8   thorpej 	while ((ic->ic_flags & IC_COMPLETE) == 0) {
   1225        1.8   thorpej 		if ((rv = tsleep(ic, PRIBIO, "icpwuccb", mstohz(timo))) != 0) {
   1226        1.8   thorpej 			splx(s);
   1227        1.8   thorpej 			return (rv);
   1228        1.8   thorpej 		}
   1229        1.8   thorpej 	}
   1230        1.8   thorpej 	splx(s);
   1231        1.8   thorpej 
   1232        1.8   thorpej 	return (0);
   1233        1.8   thorpej }
   1234        1.8   thorpej 
   1235        1.1        ad void
   1236        1.1        ad icp_ccb_submit(struct icp_softc *icp, struct icp_ccb *ic)
   1237        1.1        ad {
   1238        1.1        ad 
   1239        1.1        ad 	ic->ic_cmdlen = (ic->ic_cmdlen + 3) & ~3;
   1240        1.1        ad 
   1241        1.1        ad 	(*icp->icp_set_sema0)(icp);
   1242        1.1        ad 	DELAY(10);
   1243        1.1        ad 
   1244        1.1        ad 	ic->ic_cmd.cmd_boardnode = htole32(ICP_LOCALBOARD);
   1245        1.1        ad 	ic->ic_cmd.cmd_cmdindex = htole32(ic->ic_ident);
   1246        1.1        ad 
   1247       1.10   thorpej 	icp->icp_running++;
   1248       1.10   thorpej 
   1249        1.1        ad 	(*icp->icp_copy_cmd)(icp, ic);
   1250        1.1        ad 	(*icp->icp_release_event)(icp, ic);
   1251       1.10   thorpej }
   1252       1.10   thorpej 
   1253       1.10   thorpej int
   1254       1.10   thorpej icp_freeze(struct icp_softc *icp)
   1255       1.10   thorpej {
   1256       1.10   thorpej 	int s, error = 0;
   1257       1.10   thorpej 
   1258       1.10   thorpej 	s = splbio();
   1259       1.10   thorpej 	if (icp->icp_qfreeze++ == 0) {
   1260       1.10   thorpej 		while (icp->icp_running != 0) {
   1261       1.10   thorpej 			icp->icp_flags |= ICP_F_WAIT_FREEZE;
   1262       1.10   thorpej 			error = tsleep(&icp->icp_qfreeze, PRIBIO|PCATCH,
   1263       1.10   thorpej 			    "icpqfrz", 0);
   1264       1.10   thorpej 			if (error != 0 && --icp->icp_qfreeze == 0 &&
   1265       1.10   thorpej 			    ICP_HAS_WORK(icp)) {
   1266       1.10   thorpej 				icp_ccb_enqueue(icp, NULL);
   1267       1.10   thorpej 				break;
   1268       1.10   thorpej 			}
   1269       1.10   thorpej 		}
   1270       1.10   thorpej 	}
   1271       1.10   thorpej 	splx(s);
   1272       1.10   thorpej 
   1273       1.10   thorpej 	return (error);
   1274       1.10   thorpej }
   1275       1.10   thorpej 
   1276       1.10   thorpej void
   1277       1.10   thorpej icp_unfreeze(struct icp_softc *icp)
   1278       1.10   thorpej {
   1279       1.10   thorpej 	int s;
   1280       1.10   thorpej 
   1281       1.10   thorpej 	s = splbio();
   1282       1.10   thorpej 	KDASSERT(icp->icp_qfreeze != 0);
   1283       1.10   thorpej 	if (--icp->icp_qfreeze == 0 && ICP_HAS_WORK(icp))
   1284       1.10   thorpej 		icp_ccb_enqueue(icp, NULL);
   1285       1.10   thorpej 	splx(s);
   1286        1.8   thorpej }
   1287        1.8   thorpej 
   1288        1.8   thorpej /* XXX Global - should be per-controller? XXX */
   1289        1.8   thorpej static gdt_evt_str icp_event_buffer[ICP_MAX_EVENTS];
   1290        1.8   thorpej static int icp_event_oldidx;
   1291        1.8   thorpej static int icp_event_lastidx;
   1292        1.8   thorpej 
   1293        1.8   thorpej gdt_evt_str *
   1294       1.22  christos icp_store_event(struct icp_softc *icp, u_int16_t source, u_int16_t idx,
   1295        1.8   thorpej     gdt_evt_data *evt)
   1296        1.8   thorpej {
   1297        1.8   thorpej 	gdt_evt_str *e;
   1298        1.8   thorpej 
   1299        1.8   thorpej 	/* no source == no event */
   1300        1.8   thorpej 	if (source == 0)
   1301        1.8   thorpej 		return (NULL);
   1302        1.8   thorpej 
   1303        1.8   thorpej 	e = &icp_event_buffer[icp_event_lastidx];
   1304        1.8   thorpej 	if (e->event_source == source && e->event_idx == idx &&
   1305        1.8   thorpej 	    ((evt->size != 0 && e->event_data.size != 0 &&
   1306        1.8   thorpej 	      memcmp(&e->event_data.eu, &evt->eu, evt->size) == 0) ||
   1307        1.8   thorpej 	     (evt->size == 0 && e->event_data.size == 0 &&
   1308        1.8   thorpej 	      strcmp((char *) e->event_data.event_string,
   1309        1.8   thorpej 	      	     (char *) evt->event_string) == 0))) {
   1310       1.20    kardel 		e->last_stamp = time_second;
   1311        1.8   thorpej 		e->same_count++;
   1312        1.8   thorpej 	} else {
   1313        1.8   thorpej 		if (icp_event_buffer[icp_event_lastidx].event_source != 0) {
   1314        1.8   thorpej 			icp_event_lastidx++;
   1315        1.8   thorpej 			if (icp_event_lastidx == ICP_MAX_EVENTS)
   1316        1.8   thorpej 				icp_event_lastidx = 0;
   1317        1.8   thorpej 			if (icp_event_lastidx == icp_event_oldidx) {
   1318        1.8   thorpej 				icp_event_oldidx++;
   1319        1.8   thorpej 				if (icp_event_oldidx == ICP_MAX_EVENTS)
   1320        1.8   thorpej 					icp_event_oldidx = 0;
   1321        1.8   thorpej 			}
   1322        1.8   thorpej 		}
   1323        1.8   thorpej 		e = &icp_event_buffer[icp_event_lastidx];
   1324        1.8   thorpej 		e->event_source = source;
   1325        1.8   thorpej 		e->event_idx = idx;
   1326       1.20    kardel 		e->first_stamp = e->last_stamp = time_second;
   1327        1.8   thorpej 		e->same_count = 1;
   1328        1.8   thorpej 		e->event_data = *evt;
   1329        1.8   thorpej 		e->application = 0;
   1330        1.8   thorpej 	}
   1331        1.8   thorpej 	return (e);
   1332        1.8   thorpej }
   1333        1.8   thorpej 
   1334        1.8   thorpej int
   1335       1.22  christos icp_read_event(struct icp_softc *icp, int handle, gdt_evt_str *estr)
   1336        1.8   thorpej {
   1337        1.8   thorpej 	gdt_evt_str *e;
   1338        1.8   thorpej 	int eindex, s;
   1339        1.8   thorpej 
   1340        1.8   thorpej 	s = splbio();
   1341        1.8   thorpej 
   1342        1.8   thorpej 	if (handle == -1)
   1343        1.8   thorpej 		eindex = icp_event_oldidx;
   1344        1.8   thorpej 	else
   1345        1.8   thorpej 		eindex = handle;
   1346        1.8   thorpej 
   1347        1.8   thorpej 	estr->event_source = 0;
   1348        1.8   thorpej 
   1349        1.8   thorpej 	if (eindex < 0 || eindex >= ICP_MAX_EVENTS) {
   1350        1.8   thorpej 		splx(s);
   1351        1.8   thorpej 		return (eindex);
   1352        1.8   thorpej 	}
   1353        1.8   thorpej 
   1354        1.8   thorpej 	e = &icp_event_buffer[eindex];
   1355        1.8   thorpej 	if (e->event_source != 0) {
   1356        1.8   thorpej 		if (eindex != icp_event_lastidx) {
   1357        1.8   thorpej 			eindex++;
   1358        1.8   thorpej 			if (eindex == ICP_MAX_EVENTS)
   1359        1.8   thorpej 				eindex = 0;
   1360        1.8   thorpej 		} else
   1361        1.8   thorpej 			eindex = -1;
   1362        1.8   thorpej 		memcpy(estr, e, sizeof(gdt_evt_str));
   1363        1.8   thorpej 	}
   1364        1.8   thorpej 
   1365        1.8   thorpej 	splx(s);
   1366        1.8   thorpej 
   1367        1.8   thorpej 	return (eindex);
   1368        1.8   thorpej }
   1369        1.8   thorpej 
   1370        1.8   thorpej void
   1371       1.22  christos icp_readapp_event(struct icp_softc *icp, u_int8_t application,
   1372        1.8   thorpej     gdt_evt_str *estr)
   1373        1.8   thorpej {
   1374        1.8   thorpej 	gdt_evt_str *e;
   1375        1.8   thorpej 	int found = 0, eindex, s;
   1376        1.8   thorpej 
   1377        1.8   thorpej 	s = splbio();
   1378        1.8   thorpej 
   1379        1.8   thorpej 	eindex = icp_event_oldidx;
   1380        1.8   thorpej 	for (;;) {
   1381        1.8   thorpej 		e = &icp_event_buffer[eindex];
   1382        1.8   thorpej 		if (e->event_source == 0)
   1383        1.8   thorpej 			break;
   1384        1.8   thorpej 		if ((e->application & application) == 0) {
   1385        1.8   thorpej 			e->application |= application;
   1386        1.8   thorpej 			found = 1;
   1387        1.8   thorpej 			break;
   1388        1.8   thorpej 		}
   1389        1.8   thorpej 		if (eindex == icp_event_lastidx)
   1390        1.8   thorpej 			break;
   1391        1.8   thorpej 		eindex++;
   1392        1.8   thorpej 		if (eindex == ICP_MAX_EVENTS)
   1393        1.8   thorpej 			eindex = 0;
   1394        1.8   thorpej 	}
   1395        1.8   thorpej 	if (found)
   1396        1.8   thorpej 		memcpy(estr, e, sizeof(gdt_evt_str));
   1397        1.8   thorpej 	else
   1398        1.8   thorpej 		estr->event_source = 0;
   1399        1.8   thorpej 
   1400        1.8   thorpej 	splx(s);
   1401        1.8   thorpej }
   1402        1.8   thorpej 
   1403        1.8   thorpej void
   1404       1.22  christos icp_clear_events(struct icp_softc *icp)
   1405        1.8   thorpej {
   1406        1.8   thorpej 	int s;
   1407        1.8   thorpej 
   1408        1.8   thorpej 	s = splbio();
   1409        1.8   thorpej 	icp_event_oldidx = icp_event_lastidx = 0;
   1410        1.8   thorpej 	memset(icp_event_buffer, 0, sizeof(icp_event_buffer));
   1411        1.8   thorpej 	splx(s);
   1412        1.1        ad }
   1413