Home | History | Annotate | Line # | Download | only in ic
mlx.c revision 1.16
      1 /*	$NetBSD: mlx.c,v 1.16 2002/04/23 11:57:45 ad Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Andrew Doran.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 /*-
     40  * Copyright (c) 1999 Michael Smith
     41  * All rights reserved.
     42  *
     43  * Redistribution and use in source and binary forms, with or without
     44  * modification, are permitted provided that the following conditions
     45  * are met:
     46  * 1. Redistributions of source code must retain the above copyright
     47  *    notice, this list of conditions and the following disclaimer.
     48  * 2. Redistributions in binary form must reproduce the above copyright
     49  *    notice, this list of conditions and the following disclaimer in the
     50  *    documentation and/or other materials provided with the distribution.
     51  *
     52  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     53  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     55  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     56  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     57  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     58  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     59  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     60  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     61  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     62  * SUCH DAMAGE.
     63  *
     64  * from FreeBSD: mlx.c,v 1.14.2.3 2000/08/04 06:52:50 msmith Exp
     65  */
     66 
     67 /*
     68  * Driver for the Mylex DAC960 family of RAID controllers.
     69  *
     70  * TODO:
     71  *
     72  * o Test and enable channel pause.
     73  * o SCSI pass-through.
     74  */
     75 
     76 #include <sys/cdefs.h>
     77 __KERNEL_RCSID(0, "$NetBSD: mlx.c,v 1.16 2002/04/23 11:57:45 ad Exp $");
     78 
     79 #include "ld.h"
     80 
     81 #include <sys/param.h>
     82 #include <sys/systm.h>
     83 #include <sys/kernel.h>
     84 #include <sys/device.h>
     85 #include <sys/queue.h>
     86 #include <sys/proc.h>
     87 #include <sys/buf.h>
     88 #include <sys/endian.h>
     89 #include <sys/malloc.h>
     90 #include <sys/conf.h>
     91 #include <sys/kthread.h>
     92 #include <sys/disk.h>
     93 
     94 #include <machine/vmparam.h>
     95 #include <machine/bus.h>
     96 
     97 #include <uvm/uvm_extern.h>
     98 
     99 #include <dev/ldvar.h>
    100 
    101 #include <dev/ic/mlxreg.h>
    102 #include <dev/ic/mlxio.h>
    103 #include <dev/ic/mlxvar.h>
    104 
    105 #define	MLX_TIMEOUT	60
    106 
    107 #ifdef DIAGNOSTIC
    108 #define	DPRINTF(x)	printf x
    109 #else
    110 #define	DPRINTF(x)
    111 #endif
    112 
    113 static void	mlx_adjqparam(struct mlx_softc *, int, int);
    114 static int	mlx_ccb_submit(struct mlx_softc *, struct mlx_ccb *);
    115 static int	mlx_check(struct mlx_softc *, int);
    116 static void	mlx_configure(struct mlx_softc *, int);
    117 static void	mlx_describe(struct mlx_softc *);
    118 static void	*mlx_enquire(struct mlx_softc *, int, size_t,
    119 			     void (*)(struct mlx_ccb *), int);
    120 static int	mlx_fw_message(struct mlx_softc *, int, int, int);
    121 static void	mlx_pause_action(struct mlx_softc *);
    122 static void	mlx_pause_done(struct mlx_ccb *);
    123 static void	mlx_periodic(struct mlx_softc *);
    124 static void	mlx_periodic_create(void *);
    125 static void	mlx_periodic_enquiry(struct mlx_ccb *);
    126 static void	mlx_periodic_eventlog_poll(struct mlx_softc *);
    127 static void	mlx_periodic_eventlog_respond(struct mlx_ccb *);
    128 static void	mlx_periodic_rebuild(struct mlx_ccb *);
    129 static void	mlx_periodic_thread(void *);
    130 static int	mlx_print(void *, const char *);
    131 static int	mlx_rebuild(struct mlx_softc *, int, int);
    132 static void	mlx_shutdown(void *);
    133 static int	mlx_submatch(struct device *, struct cfdata *, void *);
    134 static int	mlx_user_command(struct mlx_softc *, struct mlx_usercommand *);
    135 
    136 static __inline__ time_t	mlx_curtime(void);
    137 
    138 cdev_decl(mlx);
    139 
    140 extern struct	cfdriver mlx_cd;
    141 static struct	proc *mlx_periodic_proc;
    142 static void	*mlx_sdh;
    143 
    144 struct {
    145 	int	hwid;
    146 	const char	*name;
    147 } static const mlx_cname[] = {
    148 	{ 0x01, "960P/PD" },
    149 	{ 0x02,	"960PL" },
    150 	{ 0x10, "960PG" },
    151 	{ 0x11, "960PJ" },
    152 	{ 0x12, "960PR" },
    153 	{ 0x13,	"960PT" },
    154 	{ 0x14, "960PTL0" },
    155 	{ 0x15, "960PRL" },
    156 	{ 0x16, "960PTL1" },
    157 	{ 0x20, "1164PVX" },
    158 };
    159 
    160 static const char * const mlx_sense_msgs[] = {
    161 	"because write recovery failed",
    162 	"because of SCSI bus reset failure",
    163 	"because of double check condition",
    164 	"because it was removed",
    165 	"because of gross error on SCSI chip",
    166 	"because of bad tag returned from drive",
    167 	"because of timeout on SCSI command",
    168 	"because of reset SCSI command issued from system",
    169 	"because busy or parity error count exceeded limit",
    170 	"because of 'kill drive' command from system",
    171 	"because of selection timeout",
    172 	"due to SCSI phase sequence error",
    173 	"due to unknown status"
    174 };
    175 
    176 static const char * const mlx_status_msgs[] = {
    177 	"normal completion",				/* 0 */
    178 	"irrecoverable data error",			/* 1 */
    179 	"drive does not exist, or is offline",		/* 2 */
    180 	"attempt to write beyond end of drive",		/* 3 */
    181 	"bad data encountered",				/* 4 */
    182 	"invalid log entry request",			/* 5 */
    183 	"attempt to rebuild online drive",		/* 6 */
    184 	"new disk failed during rebuild",		/* 7 */
    185 	"invalid channel/target",			/* 8 */
    186 	"rebuild/check already in progress",		/* 9 */
    187 	"one or more disks are dead",			/* 10 */
    188 	"invalid or non-redundant drive",		/* 11 */
    189 	"channel is busy",				/* 12 */
    190 	"channel is not stopped",			/* 13 */
    191 	"rebuild successfully terminated",		/* 14 */
    192 	"unsupported command",				/* 15 */
    193 	"check condition received",			/* 16 */
    194 	"device is busy",				/* 17 */
    195 	"selection or command timeout",			/* 18 */
    196 	"command terminated abnormally",		/* 19 */
    197 	"controller wedged",				/* 20 */
    198 	"software timeout",				/* 21 */
    199 	"command busy (?)",				/* 22 */
    200 };
    201 
    202 struct {
    203 	u_char	command;
    204 	u_char	msg;		/* Index into mlx_status_msgs[]. */
    205 	u_short	status;
    206 } static const mlx_msgs[] = {
    207 	{ MLX_CMD_READSG,	1,	0x0001 },
    208 	{ MLX_CMD_READSG,	1,	0x0002 },
    209 	{ MLX_CMD_READSG,	3,	0x0105 },
    210 	{ MLX_CMD_READSG,	4,	0x010c },
    211 	{ MLX_CMD_WRITESG,	1,	0x0001 },
    212 	{ MLX_CMD_WRITESG,	1,	0x0002 },
    213 	{ MLX_CMD_WRITESG,	3,	0x0105 },
    214 	{ MLX_CMD_READSG_OLD,	1,	0x0001 },
    215 	{ MLX_CMD_READSG_OLD,	1,	0x0002 },
    216 	{ MLX_CMD_READSG_OLD,	3,	0x0105 },
    217 	{ MLX_CMD_WRITESG_OLD,	1,	0x0001 },
    218 	{ MLX_CMD_WRITESG_OLD,	1,	0x0002 },
    219 	{ MLX_CMD_WRITESG_OLD,	3,	0x0105 },
    220 	{ MLX_CMD_LOGOP,	5,	0x0105 },
    221 	{ MLX_CMD_REBUILDASYNC,	6,	0x0002 },
    222 	{ MLX_CMD_REBUILDASYNC,	7,	0x0004 },
    223 	{ MLX_CMD_REBUILDASYNC,	8,	0x0105 },
    224 	{ MLX_CMD_REBUILDASYNC,	9,	0x0106 },
    225 	{ MLX_CMD_REBUILDASYNC,	14,	0x0107 },
    226 	{ MLX_CMD_CHECKASYNC,	10,	0x0002 },
    227 	{ MLX_CMD_CHECKASYNC,	11,	0x0105 },
    228 	{ MLX_CMD_CHECKASYNC,	9,	0x0106 },
    229 	{ MLX_CMD_STOPCHANNEL,	12,	0x0106 },
    230 	{ MLX_CMD_STOPCHANNEL,	8,	0x0105 },
    231 	{ MLX_CMD_STARTCHANNEL,	13,	0x0005 },
    232 	{ MLX_CMD_STARTCHANNEL,	8,	0x0105 },
    233 	{ MLX_CMD_DIRECT_CDB,	16,	0x0002 },
    234 	{ MLX_CMD_DIRECT_CDB,	17,	0x0008 },
    235 	{ MLX_CMD_DIRECT_CDB,	18,	0x000e },
    236 	{ MLX_CMD_DIRECT_CDB,	19,	0x000f },
    237 	{ MLX_CMD_DIRECT_CDB,	8,	0x0105 },
    238 
    239 	{ 0,			20,	MLX_STATUS_WEDGED },
    240 	{ 0,			21,	MLX_STATUS_LOST },
    241 	{ 0,			22,	MLX_STATUS_BUSY },
    242 
    243 	{ 0,			14,	0x0104 },
    244 };
    245 
    246 /*
    247  * Return the current time in seconds - we're not particularly interested in
    248  * precision here.
    249  */
    250 static __inline__ time_t
    251 mlx_curtime(void)
    252 {
    253 	time_t rt;
    254 	int s;
    255 
    256 	s = splclock();
    257 	rt = mono_time.tv_sec;
    258 	splx(s);
    259 
    260 	return (rt);
    261 }
    262 
    263 /*
    264  * Initialise the controller and our interface.
    265  */
    266 void
    267 mlx_init(struct mlx_softc *mlx, const char *intrstr)
    268 {
    269 	struct mlx_ccb *mc;
    270 	struct mlx_enquiry_old *meo;
    271 	int rv, fwminor, hscode, hserr, hsparam1, hsparam2, hsmsg;
    272 	int size, i, rseg;
    273 	const char *wantfwstr;
    274 	bus_dma_segment_t seg;
    275 
    276 	SIMPLEQ_INIT(&mlx->mlx_ccb_queue);
    277 	SLIST_INIT(&mlx->mlx_ccb_freelist);
    278 	TAILQ_INIT(&mlx->mlx_ccb_worklist);
    279 
    280 	if (intrstr != NULL)
    281 		printf("%s: interrupting at %s\n", mlx->mlx_dv.dv_xname,
    282 		    intrstr);
    283 
    284 	/*
    285 	 * Allocate the scatter/gather lists.
    286 	 */
    287         size = MLX_SGL_SIZE * MLX_MAX_QUEUECNT;
    288 
    289 	if ((rv = bus_dmamem_alloc(mlx->mlx_dmat, size, PAGE_SIZE, 0, &seg, 1,
    290 	    &rseg, BUS_DMA_NOWAIT)) != 0) {
    291 		printf("%s: unable to allocate sglists, rv = %d\n",
    292 		    mlx->mlx_dv.dv_xname, rv);
    293 		return;
    294 	}
    295 
    296 	if ((rv = bus_dmamem_map(mlx->mlx_dmat, &seg, rseg, size,
    297 	    (caddr_t *)&mlx->mlx_sgls,
    298 	    BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
    299 		printf("%s: unable to map sglists, rv = %d\n",
    300 		    mlx->mlx_dv.dv_xname, rv);
    301 		return;
    302 	}
    303 
    304 	if ((rv = bus_dmamap_create(mlx->mlx_dmat, size, 1, size, 0,
    305 	    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &mlx->mlx_dmamap)) != 0) {
    306 		printf("%s: unable to create sglist DMA map, rv = %d\n",
    307 		    mlx->mlx_dv.dv_xname, rv);
    308 		return;
    309 	}
    310 
    311 	if ((rv = bus_dmamap_load(mlx->mlx_dmat, mlx->mlx_dmamap,
    312 	    mlx->mlx_sgls, size, NULL, BUS_DMA_NOWAIT)) != 0) {
    313 		printf("%s: unable to load sglist DMA map, rv = %d\n",
    314 		    mlx->mlx_dv.dv_xname, rv);
    315 		return;
    316 	}
    317 
    318 	mlx->mlx_sgls_paddr = mlx->mlx_dmamap->dm_segs[0].ds_addr;
    319 	memset(mlx->mlx_sgls, 0, size);
    320 
    321 	/*
    322 	 * Allocate and initialize the CCBs.
    323 	 */
    324 	mc = malloc(sizeof(*mc) * MLX_MAX_QUEUECNT, M_DEVBUF, M_NOWAIT);
    325 	mlx->mlx_ccbs = mc;
    326 
    327 	for (i = 0; i < MLX_MAX_QUEUECNT; i++, mc++) {
    328 		mc->mc_ident = i;
    329 		rv = bus_dmamap_create(mlx->mlx_dmat, MLX_MAX_XFER,
    330 		    MLX_MAX_SEGS, MLX_MAX_XFER, 0,
    331 		    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
    332 		    &mc->mc_xfer_map);
    333 		if (rv != 0)
    334 			break;
    335 		mlx->mlx_nccbs++;
    336 		mlx_ccb_free(mlx, mc);
    337 	}
    338 	if (mlx->mlx_nccbs != MLX_MAX_QUEUECNT)
    339 		printf("%s: %d/%d CCBs usable\n", mlx->mlx_dv.dv_xname,
    340 		    mlx->mlx_nccbs, MLX_MAX_QUEUECNT);
    341 
    342 	/* Disable interrupts before we start talking to the controller */
    343 	(*mlx->mlx_intaction)(mlx, 0);
    344 
    345 	/* If we've got a reset routine, then reset the controller now. */
    346 	if (mlx->mlx_reset != NULL) {
    347 		printf("%s: resetting controller...\n", mlx->mlx_dv.dv_xname);
    348 		if ((*mlx->mlx_reset)(mlx) != 0) {
    349 			printf("%s: reset failed\n", mlx->mlx_dv.dv_xname);
    350 			return;
    351 		}
    352 	}
    353 
    354 	/*
    355 	 * Wait for the controller to come ready, handshaking with the
    356 	 * firmware if required.  This is typically only necessary on
    357 	 * platforms where the controller BIOS does not run.
    358 	 */
    359 	hsmsg = 0;
    360 
    361 	for (;;) {
    362 		hscode = (*mlx->mlx_fw_handshake)(mlx, &hserr, &hsparam1,
    363 		    &hsparam2);
    364 		if (hscode == 0) {
    365 			if (hsmsg != 0)
    366 				printf("%s: initialization complete\n",
    367 				    mlx->mlx_dv.dv_xname);
    368 			break;
    369 		}
    370 
    371 		/* Report first time around... */
    372 		if (hsmsg == 0) {
    373 			printf("%s: initializing (may take some time)...\n",
    374 			    mlx->mlx_dv.dv_xname);
    375 			hsmsg = 1;
    376 		}
    377 
    378 		/* Did we get a real message? */
    379 		if (hscode == 2) {
    380 			hscode = mlx_fw_message(mlx, hserr, hsparam1, hsparam2);
    381 
    382 			/* Fatal initialisation error? */
    383 			if (hscode != 0)
    384 				return;
    385 		}
    386 	}
    387 
    388 	/* Send an ENQUIRY2 request to the controller... */
    389 	mlx->mlx_enq2 = mlx_enquire(mlx, MLX_CMD_ENQUIRY2,
    390 	    sizeof(struct mlx_enquiry2), NULL, 0);
    391 	if (mlx->mlx_enq2 == NULL) {
    392 		printf("%s: ENQUIRY2 failed\n", mlx->mlx_dv.dv_xname);
    393 		return;
    394 	}
    395 
    396 	/*
    397 	 * Do quirk/feature related things.
    398 	 */
    399 	switch (mlx->mlx_iftype) {
    400 	case 2:
    401 		/*
    402 		 * These controllers may not report the firmware version in
    403 		 * the ENQUIRY2 response.
    404 		 */
    405 		meo = mlx_enquire(mlx, MLX_CMD_ENQUIRY_OLD,
    406 		    sizeof(struct mlx_enquiry_old), NULL, 0);
    407 		if (meo == NULL) {
    408 			printf("%s: ENQUIRY_OLD failed\n", mlx->mlx_dv.dv_xname);
    409 			return;
    410 		}
    411 		mlx->mlx_enq2->me_firmware_id[0] = meo->me_fwmajor;
    412 		mlx->mlx_enq2->me_firmware_id[1] = meo->me_fwminor;
    413 		mlx->mlx_enq2->me_firmware_id[2] = 0;
    414 		mlx->mlx_enq2->me_firmware_id[3] = '0';
    415 		free(meo, M_DEVBUF);
    416 	}
    417 
    418 	wantfwstr = NULL;
    419 	fwminor = mlx->mlx_enq2->me_firmware_id[1];
    420 
    421 	switch (mlx->mlx_enq2->me_firmware_id[0]) {
    422 	case 2:
    423 		if ((mlx->mlx_flags & MLXF_EISA) != 0) {
    424 			if (fwminor < 14)
    425 				wantfwstr = "2.14";
    426 		} else if (fwminor < 42)
    427 			wantfwstr = "2.42";
    428 		break;
    429 
    430 	case 3:
    431 		if (fwminor < 51)
    432 			wantfwstr = "3.51";
    433 		break;
    434 
    435 	case 4:
    436 		if (fwminor < 6)
    437 			wantfwstr = "4.06";
    438 		break;
    439 
    440 	case 5:
    441 		if (fwminor < 7)
    442 			wantfwstr = "5.07";
    443 		break;
    444 	}
    445 
    446 	/* Print a little information about the controller. */
    447 	mlx_describe(mlx);
    448 
    449 	if (wantfwstr != NULL) {
    450 		printf("%s: WARNING: this f/w revision is not recommended\n",
    451 		    mlx->mlx_dv.dv_xname);
    452 		printf("%s: WARNING: use revision %s or later\n",
    453 		    mlx->mlx_dv.dv_xname, wantfwstr);
    454 	}
    455 
    456 	/* We don't (yet) know where the event log is up to. */
    457 	mlx->mlx_currevent = -1;
    458 
    459 	/* No user-requested background operation is in progress. */
    460 	mlx->mlx_bg = 0;
    461 	mlx->mlx_rebuildstat.rs_code = MLX_REBUILDSTAT_IDLE;
    462 
    463 	/* Set maximum number of queued commands for `regular' operations. */
    464 	mlx->mlx_max_queuecnt =
    465 	    min(le16toh(mlx->mlx_enq2->me_max_commands), MLX_MAX_QUEUECNT) -
    466 	    MLX_NCCBS_RESERVE;
    467 #ifdef DIAGNOSTIC
    468 	if (mlx->mlx_max_queuecnt < MLX_NCCBS_RESERVE + MLX_MAX_DRIVES)
    469 		printf("%s: WARNING: few CCBs available\n",
    470 		    mlx->mlx_dv.dv_xname);
    471 	if (le16toh(mlx->mlx_enq2->me_max_sg) < MLX_MAX_SEGS) {
    472 		printf("%s: oops, not enough S/G segments\n",
    473 		    mlx->mlx_dv.dv_xname);
    474 		return;
    475 	}
    476 #endif
    477 
    478 	if (mlx_sdh == NULL) {
    479 		/*
    480 		 * Set our `shutdownhook' before we start any device
    481 		 * activity.
    482 		 */
    483 		mlx_sdh = shutdownhook_establish(mlx_shutdown, NULL);
    484 
    485 		/* Arrange to create a status monitoring thread. */
    486 		kthread_create(mlx_periodic_create, NULL);
    487 	}
    488 
    489 	/* Finally, attach child devices and enable interrupts. */
    490 	mlx_configure(mlx, 0);
    491 	(*mlx->mlx_intaction)(mlx, 1);
    492 
    493 	mlx->mlx_flags |= MLXF_INITOK;
    494 }
    495 
    496 /*
    497  * Tell the world about the controller.
    498  */
    499 static void
    500 mlx_describe(struct mlx_softc *mlx)
    501 {
    502 	struct mlx_enquiry2 *me;
    503 	static char buf[80];
    504 	const char *model;
    505 	int i;
    506 
    507 	model = NULL;
    508 	me = mlx->mlx_enq2;
    509 
    510 	for (i = 0; i < sizeof(mlx_cname) / sizeof(mlx_cname[0]); i++)
    511 		if (me->me_hardware_id[0] == mlx_cname[i].hwid) {
    512 			model = mlx_cname[i].name;
    513 			break;
    514 		}
    515 
    516 	if (model == NULL) {
    517 		sprintf(buf, " model 0x%x", me->me_hardware_id[0]);
    518 		model = buf;
    519 	}
    520 
    521 	printf("%s: DAC%s, %d channel%s, firmware %d.%02d-%c-%02d, %dMB RAM\n",
    522 	    mlx->mlx_dv.dv_xname, model, me->me_actual_channels,
    523 	    me->me_actual_channels > 1 ? "s" : "",
    524 	    me->me_firmware_id[0], me->me_firmware_id[1],
    525 	    me->me_firmware_id[3], me->me_firmware_id[2],
    526 	    le32toh(me->me_mem_size) >> 20);
    527 }
    528 
    529 /*
    530  * Locate disk resources and attach children to them.
    531  */
    532 static void
    533 mlx_configure(struct mlx_softc *mlx, int waitok)
    534 {
    535 	struct mlx_enquiry *me;
    536 	struct mlx_enquiry_old *meo;
    537 	struct mlx_enq_sys_drive *mes;
    538 	struct mlx_sysdrive *ms;
    539 	struct mlx_attach_args mlxa;
    540 	int i, nunits;
    541 	u_int size;
    542 
    543 	mlx->mlx_flags |= MLXF_RESCANNING;
    544 
    545 	if (mlx->mlx_iftype == 2) {
    546 		meo = mlx_enquire(mlx, MLX_CMD_ENQUIRY_OLD,
    547 		    sizeof(struct mlx_enquiry_old), NULL, waitok);
    548 		if (meo == NULL) {
    549 			printf("%s: ENQUIRY_OLD failed\n",
    550 			    mlx->mlx_dv.dv_xname);
    551 			goto out;
    552 		}
    553 		mlx->mlx_numsysdrives = meo->me_num_sys_drvs;
    554 		free(meo, M_DEVBUF);
    555 	} else {
    556 		me = mlx_enquire(mlx, MLX_CMD_ENQUIRY,
    557 		    sizeof(struct mlx_enquiry), NULL, waitok);
    558 		if (me == NULL) {
    559 			printf("%s: ENQUIRY failed\n", mlx->mlx_dv.dv_xname);
    560 			goto out;
    561 		}
    562 		mlx->mlx_numsysdrives = me->me_num_sys_drvs;
    563 		free(me, M_DEVBUF);
    564 	}
    565 
    566 	mes = mlx_enquire(mlx, MLX_CMD_ENQSYSDRIVE,
    567 	    sizeof(*mes) * MLX_MAX_DRIVES, NULL, waitok);
    568 	if (mes == NULL) {
    569 		printf("%s: error fetching drive status\n",
    570 		    mlx->mlx_dv.dv_xname);
    571 		free(me, M_DEVBUF);
    572 		goto out;
    573 	}
    574 
    575 	/* Allow 1 queued command per unit while re-configuring. */
    576 	mlx_adjqparam(mlx, 1, 0);
    577 
    578 	ms = &mlx->mlx_sysdrive[0];
    579 	nunits = 0;
    580 	for (i = 0; i < MLX_MAX_DRIVES; i++, ms++) {
    581 		size = le32toh(mes[i].sd_size);
    582 		ms->ms_state = mes[i].sd_state;
    583 
    584 		/*
    585 		 * If an existing device has changed in some way (e.g. no
    586 		 * longer present) then detach it.
    587 		 */
    588 		if (ms->ms_dv != NULL && (size != ms->ms_size ||
    589 		    (mes[i].sd_raidlevel & 0xf) != ms->ms_raidlevel))
    590 			config_detach(ms->ms_dv, DETACH_FORCE);
    591 
    592 		ms->ms_size = size;
    593 		ms->ms_raidlevel = mes[i].sd_raidlevel & 0xf;
    594 		ms->ms_state = mes[i].sd_state;
    595 		ms->ms_dv = NULL;
    596 
    597 		if (i >= mlx->mlx_numsysdrives)
    598 			continue;
    599 		if (size == 0xffffffffU || size == 0)
    600 			continue;
    601 
    602 		/*
    603 		 * Attach a new device.
    604 		 */
    605 		mlxa.mlxa_unit = i;
    606 		ms->ms_dv = config_found_sm(&mlx->mlx_dv, &mlxa, mlx_print,
    607 		    mlx_submatch);
    608 		nunits += (ms->ms_dv != NULL);
    609 	}
    610 
    611 	free(mes, M_DEVBUF);
    612 
    613 	if (nunits != 0)
    614 		mlx_adjqparam(mlx, mlx->mlx_max_queuecnt / nunits,
    615 		    mlx->mlx_max_queuecnt % nunits);
    616  out:
    617  	mlx->mlx_flags &= ~MLXF_RESCANNING;
    618 }
    619 
    620 /*
    621  * Print autoconfiguration message for a sub-device.
    622  */
    623 static int
    624 mlx_print(void *aux, const char *pnp)
    625 {
    626 	struct mlx_attach_args *mlxa;
    627 
    628 	mlxa = (struct mlx_attach_args *)aux;
    629 
    630 	if (pnp != NULL)
    631 		printf("block device at %s", pnp);
    632 	printf(" unit %d", mlxa->mlxa_unit);
    633 	return (UNCONF);
    634 }
    635 
    636 /*
    637  * Match a sub-device.
    638  */
    639 static int
    640 mlx_submatch(struct device *parent, struct cfdata *cf, void *aux)
    641 {
    642 	struct mlx_attach_args *mlxa;
    643 
    644 	mlxa = (struct mlx_attach_args *)aux;
    645 
    646 	if (cf->mlxacf_unit != MLXCF_UNIT_DEFAULT &&
    647 	    cf->mlxacf_unit != mlxa->mlxa_unit)
    648 		return (0);
    649 
    650 	return ((*cf->cf_attach->ca_match)(parent, cf, aux));
    651 }
    652 
    653 /*
    654  * Shut down all configured `mlx' devices.
    655  */
    656 static void
    657 mlx_shutdown(void *cookie)
    658 {
    659 	struct mlx_softc *mlx;
    660 	int i;
    661 
    662 	for (i = 0; i < mlx_cd.cd_ndevs; i++)
    663 		if ((mlx = device_lookup(&mlx_cd, i)) != NULL)
    664 			mlx_flush(mlx, 0);
    665 }
    666 
    667 /*
    668  * Adjust queue parameters for all child devices.
    669  */
    670 static void
    671 mlx_adjqparam(struct mlx_softc *mlx, int mpu, int slop)
    672 {
    673 #if NLD > 0
    674 	extern struct cfdriver ld_cd;
    675 	struct ld_softc *ld;
    676 	int i;
    677 
    678 	for (i = 0; i < ld_cd.cd_ndevs; i++) {
    679 		if ((ld = device_lookup(&ld_cd, i)) == NULL)
    680 			continue;
    681 		if (ld->sc_dv.dv_parent != &mlx->mlx_dv)
    682 			continue;
    683 		ldadjqparam(ld, mpu + (slop-- > 0));
    684 	}
    685 #endif
    686 }
    687 
    688 /*
    689  * Accept an open operation on the control device.
    690  */
    691 int
    692 mlxopen(dev_t dev, int flag, int mode, struct proc *p)
    693 {
    694 	struct mlx_softc *mlx;
    695 
    696 	if ((mlx = device_lookup(&mlx_cd, minor(dev))) == NULL)
    697 		return (ENXIO);
    698 	if ((mlx->mlx_flags & MLXF_INITOK) == 0)
    699 		return (ENXIO);
    700 	if ((mlx->mlx_flags & MLXF_OPEN) != 0)
    701 		return (EBUSY);
    702 
    703 	mlx->mlx_flags |= MLXF_OPEN;
    704 	return (0);
    705 }
    706 
    707 /*
    708  * Accept the last close on the control device.
    709  */
    710 int
    711 mlxclose(dev_t dev, int flag, int mode, struct proc *p)
    712 {
    713 	struct mlx_softc *mlx;
    714 
    715 	mlx = device_lookup(&mlx_cd, minor(dev));
    716 	mlx->mlx_flags &= ~MLXF_OPEN;
    717 	return (0);
    718 }
    719 
    720 /*
    721  * Handle control operations.
    722  */
    723 int
    724 mlxioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
    725 {
    726 	struct mlx_softc *mlx;
    727 	struct mlx_rebuild_request *rb;
    728 	struct mlx_rebuild_status *rs;
    729 	struct mlx_pause *mp;
    730 	struct mlx_sysdrive *ms;
    731 	int i, rv, *arg, result;
    732 
    733 	if (securelevel >= 2)
    734 		return (EPERM);
    735 
    736 	mlx = device_lookup(&mlx_cd, minor(dev));
    737 
    738 	rb = (struct mlx_rebuild_request *)data;
    739 	rs = (struct mlx_rebuild_status *)data;
    740 	arg = (int *)data;
    741 	rv = 0;
    742 
    743 	switch (cmd) {
    744 	case MLX_RESCAN_DRIVES:
    745 		/*
    746 		 * Scan the controller to see whether new drives have
    747 		 * appeared, or old ones disappeared.
    748 		 */
    749 		mlx_configure(mlx, 1);
    750 		return (0);
    751 
    752 	case MLX_PAUSE_CHANNEL:
    753 		/*
    754 		 * Pause one or more SCSI channels for a period of time, to
    755 		 * assist in the process of hot-swapping devices.
    756 		 *
    757 		 * Note that at least the 3.51 firmware on the DAC960PL
    758 		 * doesn't seem to do this right.
    759 		 */
    760 		if ((mlx->mlx_flags & MLXF_PAUSEWORKS) == 0)
    761 			return (EOPNOTSUPP);
    762 
    763 		mp = (struct mlx_pause *)data;
    764 
    765 		if ((mp->mp_which == MLX_PAUSE_CANCEL) &&
    766 		    (mlx->mlx_pause.mp_when != 0)) {
    767 			/* Cancel a pending pause operation. */
    768 			mlx->mlx_pause.mp_which = 0;
    769 			break;
    770 		}
    771 
    772 		/* Fix for legal channels. */
    773 		mp->mp_which &= ((1 << mlx->mlx_enq2->me_actual_channels) -1);
    774 
    775 		/* Check time values. */
    776 		if (mp->mp_when < 0 || mp->mp_when > 3600 ||
    777 		    mp->mp_howlong < 1 || mp->mp_howlong > (0xf * 30)) {
    778 			rv = EINVAL;
    779 			break;
    780 		}
    781 
    782 		/* Check for a pause currently running. */
    783 		if ((mlx->mlx_pause.mp_which != 0) &&
    784 		    (mlx->mlx_pause.mp_when == 0)) {
    785 			rv = EBUSY;
    786 			break;
    787 		}
    788 
    789 		/* Looks ok, go with it. */
    790 		mlx->mlx_pause.mp_which = mp->mp_which;
    791 		mlx->mlx_pause.mp_when = mlx_curtime() + mp->mp_when;
    792 		mlx->mlx_pause.mp_howlong =
    793 		    mlx->mlx_pause.mp_when + mp->mp_howlong;
    794 
    795 		return (0);
    796 
    797 	case MLX_COMMAND:
    798 		/*
    799 		 * Accept a command passthrough-style.
    800 		 */
    801 		return (mlx_user_command(mlx, (struct mlx_usercommand *)data));
    802 
    803 	case MLX_REBUILDASYNC:
    804 		/*
    805 		 * Start a rebuild on a given SCSI disk
    806 		 */
    807 		if (mlx->mlx_bg != 0) {
    808 			rb->rr_status = 0x0106;
    809 			rv = EBUSY;
    810 			break;
    811 		}
    812 
    813 		rb->rr_status = mlx_rebuild(mlx, rb->rr_channel, rb->rr_target);
    814 		switch (rb->rr_status) {
    815 		case 0:
    816 			rv = 0;
    817 			break;
    818 		case 0x10000:
    819 			rv = ENOMEM;	/* Couldn't set up the command. */
    820 			break;
    821 		case 0x0002:
    822 			rv = EBUSY;
    823 			break;
    824 		case 0x0104:
    825 			rv = EIO;
    826 			break;
    827 		case 0x0105:
    828 			rv = ERANGE;
    829 			break;
    830 		case 0x0106:
    831 			rv = EBUSY;
    832 			break;
    833 		default:
    834 			rv = EINVAL;
    835 			break;
    836 		}
    837 
    838 		if (rv == 0)
    839 			mlx->mlx_bg = MLX_BG_REBUILD;
    840 
    841 		return (0);
    842 
    843 	case MLX_REBUILDSTAT:
    844 		/*
    845 		 * Get the status of the current rebuild or consistency check.
    846 		 */
    847 		*rs = mlx->mlx_rebuildstat;
    848 		return (0);
    849 
    850 	case MLX_GET_SYSDRIVE:
    851 		/*
    852 		 * Return the system drive number matching the `ld' device
    853 		 * unit in (arg), if it happens to belong to us.
    854 		 */
    855 		for (i = 0; i < MLX_MAX_DRIVES; i++) {
    856 			ms = &mlx->mlx_sysdrive[i];
    857 			if (ms->ms_dv != NULL)
    858 				if (ms->ms_dv->dv_xname[2] == '0' + *arg) {
    859 					*arg = i;
    860 					return (0);
    861 				}
    862 		}
    863 		return (ENOENT);
    864 	}
    865 
    866 	switch (cmd) {
    867 	case MLXD_DETACH:
    868 	case MLXD_STATUS:
    869 	case MLXD_CHECKASYNC:
    870 		if ((u_int)*arg >= MLX_MAX_DRIVES)
    871 			return (EINVAL);
    872 		ms = &mlx->mlx_sysdrive[*arg];
    873 		if (*arg > MLX_MAX_DRIVES || ms->ms_dv == NULL)
    874 			return (ENOENT);
    875 		break;
    876 
    877 	default:
    878 		return (ENOTTY);
    879 	}
    880 
    881 	switch (cmd) {
    882 	case MLXD_DETACH:
    883 		/*
    884 		 * Disconnect from the specified drive; it may be about to go
    885 		 * away.
    886 		 */
    887 		return (config_detach(ms->ms_dv, 0));
    888 
    889 	case MLXD_STATUS:
    890 		/*
    891 		 * Return the current status of this drive.
    892 		 */
    893 		*arg = ms->ms_state;
    894 		return (0);
    895 
    896 	case MLXD_CHECKASYNC:
    897 		/*
    898 		 * Start a background consistency check on this drive.
    899 		 */
    900 		if (mlx->mlx_bg != 0) {
    901 			*arg = 0x0106;
    902 			return (EBUSY);
    903 		}
    904 
    905 		switch (result = mlx_check(mlx, *arg)) {
    906 		case 0:
    907 			rv = 0;
    908 			break;
    909 		case 0x10000:
    910 			rv = ENOMEM;	/* Couldn't set up the command. */
    911 			break;
    912 		case 0x0002:
    913 			rv = EIO;
    914 			break;
    915 		case 0x0105:
    916 			rv = ERANGE;
    917 			break;
    918 		case 0x0106:
    919 			rv = EBUSY;
    920 			break;
    921 		default:
    922 			rv = EINVAL;
    923 			break;
    924 		}
    925 
    926 		if (rv == 0)
    927 			mlx->mlx_bg = MLX_BG_CHECK;
    928 		*arg = result;
    929 		return (rv);
    930 	}
    931 
    932 	return (ENOTTY);	/* XXX shut up gcc */
    933 }
    934 
    935 /*
    936  * Fire off commands to periodically check the status of connected drives.
    937  * Check for commands that have timed out.
    938  */
    939 static void
    940 mlx_periodic_create(void *cookie)
    941 {
    942 	int rv;
    943 
    944 	rv = kthread_create1(mlx_periodic_thread, NULL, &mlx_periodic_proc,
    945 	    "mlxmonitor");
    946 	if (rv == 0)
    947 		return;
    948 
    949 	printf("mlx_periodic_create: unable to create thread (%d)\n", rv);
    950 }
    951 
    952 static void
    953 mlx_periodic_thread(void *cookie)
    954 {
    955 	struct mlx_softc *mlx;
    956 	int i;
    957 
    958 	for (;;) {
    959 		for (i = 0; i < mlx_cd.cd_ndevs; i++)
    960 			if ((mlx = device_lookup(&mlx_cd, i)) != NULL)
    961 				mlx_periodic(mlx);
    962 
    963 		tsleep(mlx_periodic_thread, PWAIT, "mlxzzz", hz);
    964 	}
    965 }
    966 
    967 static void
    968 mlx_periodic(struct mlx_softc *mlx)
    969 {
    970 	struct mlx_ccb *mc, *nmc;
    971 	int etype, s;
    972 	time_t ct;
    973 
    974 	ct = mlx_curtime();
    975 
    976 	if ((mlx->mlx_pause.mp_which != 0) &&
    977 	    (mlx->mlx_pause.mp_when > 0) &&
    978 	    (ct >= mlx->mlx_pause.mp_when)) {
    979 	    	/*
    980 	    	 * Start bus pause.
    981 	    	 */
    982 		mlx_pause_action(mlx);
    983 		mlx->mlx_pause.mp_when = 0;
    984 	} else if ((mlx->mlx_pause.mp_which != 0) &&
    985 		   (mlx->mlx_pause.mp_when == 0)) {
    986 		/*
    987 		 * Stop pause if required.
    988 		 */
    989 		if (ct >= mlx->mlx_pause.mp_howlong) {
    990 			mlx_pause_action(mlx);
    991 			mlx->mlx_pause.mp_which = 0;
    992 		}
    993 	} else if (ct > (mlx->mlx_lastpoll + 10)) {
    994 		/*
    995 		 * Run normal periodic activities...
    996 		 */
    997 		mlx->mlx_lastpoll = ct;
    998 
    999 		/*
   1000 		 * Check controller status.
   1001 		 */
   1002 		if ((mlx->mlx_flags & MLXF_PERIODIC_CTLR) == 0) {
   1003 			mlx->mlx_flags |= MLXF_PERIODIC_CTLR;
   1004 
   1005 			if (mlx->mlx_iftype == 2)
   1006 				etype = MLX_CMD_ENQUIRY_OLD;
   1007 			else
   1008 				etype =  MLX_CMD_ENQUIRY;
   1009 
   1010 			mlx_enquire(mlx, etype, max(sizeof(struct mlx_enquiry),
   1011 			    sizeof(struct mlx_enquiry_old)),
   1012 			    mlx_periodic_enquiry, 1);
   1013 		}
   1014 
   1015 		/*
   1016 		 * Check system drive status.
   1017 		 */
   1018 		if ((mlx->mlx_flags & MLXF_PERIODIC_DRIVE) == 0) {
   1019 			mlx->mlx_flags |= MLXF_PERIODIC_DRIVE;
   1020 			mlx_enquire(mlx, MLX_CMD_ENQSYSDRIVE,
   1021 			    sizeof(struct mlx_enq_sys_drive) * MLX_MAX_DRIVES,
   1022 			    mlx_periodic_enquiry, 1);
   1023 		}
   1024 	}
   1025 
   1026 	/*
   1027 	 * Get drive rebuild/check status.
   1028 	 */
   1029 	if ((mlx->mlx_flags & MLXF_PERIODIC_REBUILD) == 0) {
   1030 		mlx->mlx_flags |= MLXF_PERIODIC_REBUILD;
   1031 		mlx_enquire(mlx, MLX_CMD_REBUILDSTAT,
   1032 		    sizeof(struct mlx_rebuild_stat), mlx_periodic_rebuild, 1);
   1033 	}
   1034 
   1035 	/*
   1036 	 * Time-out busy CCBs.
   1037 	 */
   1038 	s = splbio();
   1039 	for (mc = TAILQ_FIRST(&mlx->mlx_ccb_worklist); mc != NULL; mc = nmc) {
   1040 		nmc = TAILQ_NEXT(mc, mc_chain.tailq);
   1041 		if (mc->mc_expiry > ct) {
   1042 			/*
   1043 			 * The remaining CCBs will expire after this one, so
   1044 			 * there's no point in going further.
   1045 			 */
   1046 			break;
   1047 		}
   1048 		TAILQ_REMOVE(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq);
   1049 		mc->mc_status = MLX_STATUS_LOST;
   1050 		if (mc->mc_mx.mx_handler != NULL)
   1051 			(*mc->mc_mx.mx_handler)(mc);
   1052 		else if ((mc->mc_flags & MC_WAITING) != 0)
   1053 			wakeup(mc);
   1054 	}
   1055 	splx(s);
   1056 }
   1057 
   1058 /*
   1059  * Handle the result of an ENQUIRY command instigated by periodic status
   1060  * polling.
   1061  */
   1062 static void
   1063 mlx_periodic_enquiry(struct mlx_ccb *mc)
   1064 {
   1065 	struct mlx_softc *mlx;
   1066 	struct mlx_enquiry *me;
   1067 	struct mlx_enquiry_old *meo;
   1068 	struct mlx_enq_sys_drive *mes;
   1069 	struct mlx_sysdrive *dr;
   1070 	const char *statestr;
   1071 	int i, j;
   1072 	u_int lsn;
   1073 
   1074 	mlx = (struct mlx_softc *)mc->mc_mx.mx_dv;
   1075 
   1076 	/*
   1077 	 * Command completed OK?
   1078 	 */
   1079 	if (mc->mc_status != 0) {
   1080 		printf("%s: periodic enquiry failed - %s\n",
   1081 		    mlx->mlx_dv.dv_xname, mlx_ccb_diagnose(mc));
   1082 		goto out;
   1083 	}
   1084 
   1085 	/*
   1086 	 * Respond to command.
   1087 	 */
   1088 	switch (mc->mc_mbox[0]) {
   1089 	case MLX_CMD_ENQUIRY_OLD:
   1090 		/*
   1091 		 * This is currently a bit fruitless, as we don't know how
   1092 		 * to extract the eventlog pointer yet.
   1093 		 */
   1094 		me = (struct mlx_enquiry *)mc->mc_mx.mx_context;
   1095 		meo = (struct mlx_enquiry_old *)mc->mc_mx.mx_context;
   1096 
   1097 		/* Convert data in-place to new format */
   1098 		i = sizeof(me->me_dead) / sizeof(me->me_dead[0]);
   1099 		while (--i >= 0) {
   1100 			me->me_dead[i].dd_chan = meo->me_dead[i].dd_chan;
   1101 			me->me_dead[i].dd_targ = meo->me_dead[i].dd_targ;
   1102 		}
   1103 
   1104 		me->me_misc_flags = 0;
   1105 		me->me_rebuild_count = meo->me_rebuild_count;
   1106 		me->me_dead_count = meo->me_dead_count;
   1107 		me->me_critical_sd_count = meo->me_critical_sd_count;
   1108 		me->me_event_log_seq_num = 0;
   1109 		me->me_offline_sd_count = meo->me_offline_sd_count;
   1110 		me->me_max_commands = meo->me_max_commands;
   1111 		me->me_rebuild_flag = meo->me_rebuild_flag;
   1112 		me->me_fwmajor = meo->me_fwmajor;
   1113 		me->me_fwminor = meo->me_fwminor;
   1114 		me->me_status_flags = meo->me_status_flags;
   1115 		me->me_flash_age = meo->me_flash_age;
   1116 
   1117 		i = sizeof(me->me_drvsize) / sizeof(me->me_drvsize[0]);
   1118 		j = sizeof(meo->me_drvsize) / sizeof(meo->me_drvsize[0]);
   1119 
   1120 		while (--i >= 0) {
   1121 			if (i >= j)
   1122 				me->me_drvsize[i] = 0;
   1123 			else
   1124 				me->me_drvsize[i] = meo->me_drvsize[i];
   1125 		}
   1126 
   1127 		me->me_num_sys_drvs = meo->me_num_sys_drvs;
   1128 
   1129 		/* FALLTHROUGH */
   1130 
   1131 	case MLX_CMD_ENQUIRY:
   1132 		/*
   1133 		 * Generic controller status update.  We could do more with
   1134 		 * this than just checking the event log.
   1135 		 */
   1136 		me = (struct mlx_enquiry *)mc->mc_mx.mx_context;
   1137 		lsn = le16toh(me->me_event_log_seq_num);
   1138 
   1139 		if (mlx->mlx_currevent == -1) {
   1140 			/* Initialise our view of the event log. */
   1141 			mlx->mlx_currevent = lsn;
   1142 			mlx->mlx_lastevent = lsn;
   1143 		} else if (lsn != mlx->mlx_lastevent &&
   1144 			   (mlx->mlx_flags & MLXF_EVENTLOG_BUSY) == 0) {
   1145 			/* Record where current events are up to */
   1146 			mlx->mlx_currevent = lsn;
   1147 
   1148 			/* Mark the event log as busy. */
   1149 			mlx->mlx_flags |= MLXF_EVENTLOG_BUSY;
   1150 
   1151 			/* Drain new eventlog entries. */
   1152 			mlx_periodic_eventlog_poll(mlx);
   1153 		}
   1154 		break;
   1155 
   1156 	case MLX_CMD_ENQSYSDRIVE:
   1157 		/*
   1158 		 * Perform drive status comparison to see if something
   1159 		 * has failed.  Don't perform the comparison if we're
   1160 		 * reconfiguring, since the system drive table will be
   1161 		 * changing.
   1162 		 */
   1163 		if ((mlx->mlx_flags & MLXF_RESCANNING) != 0)
   1164 			break;
   1165 
   1166 		mes = (struct mlx_enq_sys_drive *)mc->mc_mx.mx_context;
   1167 		dr = &mlx->mlx_sysdrive[0];
   1168 
   1169 		for (i = 0; i < mlx->mlx_numsysdrives; i++) {
   1170 			/* Has state been changed by controller? */
   1171 			if (dr->ms_state != mes[i].sd_state) {
   1172 				switch (mes[i].sd_state) {
   1173 				case MLX_SYSD_OFFLINE:
   1174 					statestr = "offline";
   1175 					break;
   1176 
   1177 				case MLX_SYSD_ONLINE:
   1178 					statestr = "online";
   1179 					break;
   1180 
   1181 				case MLX_SYSD_CRITICAL:
   1182 					statestr = "critical";
   1183 					break;
   1184 
   1185 				default:
   1186 					statestr = "unknown";
   1187 					break;
   1188 				}
   1189 
   1190 				printf("%s: unit %d %s\n", mlx->mlx_dv.dv_xname,
   1191 				    i, statestr);
   1192 
   1193 				/* Save new state. */
   1194 				dr->ms_state = mes[i].sd_state;
   1195 			}
   1196 		}
   1197 		break;
   1198 
   1199 #ifdef DIAGNOSTIC
   1200 	default:
   1201 		printf("%s: mlx_periodic_enquiry: eh?\n",
   1202 		    mlx->mlx_dv.dv_xname);
   1203 		break;
   1204 #endif
   1205 	}
   1206 
   1207  out:
   1208 	if (mc->mc_mbox[0] == MLX_CMD_ENQSYSDRIVE)
   1209 		mlx->mlx_flags &= ~MLXF_PERIODIC_DRIVE;
   1210 	else
   1211 		mlx->mlx_flags &= ~MLXF_PERIODIC_CTLR;
   1212 
   1213 	free(mc->mc_mx.mx_context, M_DEVBUF);
   1214 	mlx_ccb_free(mlx, mc);
   1215 }
   1216 
   1217 /*
   1218  * Instigate a poll for one event log message on (mlx).  We only poll for
   1219  * one message at a time, to keep our command usage down.
   1220  */
   1221 static void
   1222 mlx_periodic_eventlog_poll(struct mlx_softc *mlx)
   1223 {
   1224 	struct mlx_ccb *mc;
   1225 	void *result;
   1226 	int rv;
   1227 
   1228 	result = NULL;
   1229 
   1230 	if ((rv = mlx_ccb_alloc(mlx, &mc, 1)) != 0)
   1231 		goto out;
   1232 
   1233 	if ((result = malloc(1024, M_DEVBUF, M_WAITOK)) == NULL) {
   1234 		rv = ENOMEM;
   1235 		goto out;
   1236 	}
   1237 	if ((rv = mlx_ccb_map(mlx, mc, result, 1024, MC_XFER_IN)) != 0)
   1238 		goto out;
   1239 	if (mc->mc_nsgent != 1) {
   1240 		mlx_ccb_unmap(mlx, mc);
   1241 		printf("mlx_periodic_eventlog_poll: too many segs\n");
   1242 		goto out;
   1243 	}
   1244 
   1245 	/* Build the command to get one log entry. */
   1246 	mlx_make_type3(mc, MLX_CMD_LOGOP, MLX_LOGOP_GET, 1,
   1247 	    mlx->mlx_lastevent, 0, 0, mc->mc_xfer_phys, 0);
   1248 
   1249 	mc->mc_mx.mx_handler = mlx_periodic_eventlog_respond;
   1250 	mc->mc_mx.mx_dv = &mlx->mlx_dv;
   1251 	mc->mc_mx.mx_context = result;
   1252 
   1253 	/* Start the command. */
   1254 	mlx_ccb_enqueue(mlx, mc);
   1255 
   1256  out:
   1257 	if (rv != 0) {
   1258 		if (mc != NULL)
   1259 			mlx_ccb_free(mlx, mc);
   1260 		if (result != NULL)
   1261 			free(result, M_DEVBUF);
   1262 	}
   1263 }
   1264 
   1265 /*
   1266  * Handle the result of polling for a log message, generate diagnostic
   1267  * output.  If this wasn't the last message waiting for us, we'll go collect
   1268  * another.
   1269  */
   1270 static void
   1271 mlx_periodic_eventlog_respond(struct mlx_ccb *mc)
   1272 {
   1273 	struct mlx_softc *mlx;
   1274 	struct mlx_eventlog_entry *el;
   1275 	const char *reason;
   1276 	u_int8_t sensekey, chan, targ;
   1277 
   1278 	mlx = (struct mlx_softc *)mc->mc_mx.mx_dv;
   1279 	el = mc->mc_mx.mx_context;
   1280 	mlx_ccb_unmap(mlx, mc);
   1281 
   1282 	mlx->mlx_lastevent++;
   1283 
   1284 	if (mc->mc_status == 0) {
   1285 		switch (el->el_type) {
   1286 		case MLX_LOGMSG_SENSE:		/* sense data */
   1287 			sensekey = el->el_sense & 0x0f;
   1288 			chan = (el->el_target >> 4) & 0x0f;
   1289 			targ = el->el_target & 0x0f;
   1290 
   1291 			/*
   1292 			 * This is the only sort of message we understand at
   1293 			 * the moment.  The tests here are probably
   1294 			 * incomplete.
   1295 			 */
   1296 
   1297 			/*
   1298 			 * Mylex vendor-specific message indicating a drive
   1299 			 * was killed?
   1300 			 */
   1301 			if (sensekey == 9 && el->el_asc == 0x80) {
   1302 				if (el->el_asq < sizeof(mlx_sense_msgs) /
   1303 				    sizeof(mlx_sense_msgs[0]))
   1304 					reason = mlx_sense_msgs[el->el_asq];
   1305 				else
   1306 					reason = "for unknown reason";
   1307 
   1308 				printf("%s: physical drive %d:%d killed %s\n",
   1309 				    mlx->mlx_dv.dv_xname, chan, targ, reason);
   1310 			}
   1311 
   1312 			/*
   1313 			 * SCSI drive was reset?
   1314 			 */
   1315 			if (sensekey == 6 && el->el_asc == 0x29)
   1316 				printf("%s: physical drive %d:%d reset\n",
   1317 				    mlx->mlx_dv.dv_xname, chan, targ);
   1318 
   1319 			/*
   1320 			 * SCSI drive error?
   1321 			 */
   1322 			if (!(sensekey == 0 ||
   1323 			    (sensekey == 2 &&
   1324 			    el->el_asc == 0x04 &&
   1325 			    (el->el_asq == 0x01 || el->el_asq == 0x02)))) {
   1326 				printf("%s: physical drive %d:%d error log: "
   1327 				    "sense = %d asc = %x asq = %x\n",
   1328 				    mlx->mlx_dv.dv_xname, chan, targ, sensekey,
   1329 				    el->el_asc, el->el_asq);
   1330 				printf("%s:   info = %d:%d:%d:%d "
   1331 				    " csi = %d:%d:%d:%d\n",
   1332 				    mlx->mlx_dv.dv_xname,
   1333 				    el->el_information[0],
   1334 				    el->el_information[1],
   1335 				    el->el_information[2],
   1336 				    el->el_information[3],
   1337 				    el->el_csi[0], el->el_csi[1],
   1338 				    el->el_csi[2], el->el_csi[3]);
   1339 			}
   1340 
   1341 			break;
   1342 
   1343 		default:
   1344 			printf("%s: unknown log message type 0x%x\n",
   1345 			    mlx->mlx_dv.dv_xname, el->el_type);
   1346 			break;
   1347 		}
   1348 	} else {
   1349 		printf("%s: error reading message log - %s\n",
   1350 		    mlx->mlx_dv.dv_xname, mlx_ccb_diagnose(mc));
   1351 
   1352 		/*
   1353 		 * Give up on all the outstanding messages, as we may have
   1354 		 * come unsynched.
   1355 		 */
   1356 		mlx->mlx_lastevent = mlx->mlx_currevent;
   1357 	}
   1358 
   1359 	free(mc->mc_mx.mx_context, M_DEVBUF);
   1360 	mlx_ccb_free(mlx, mc);
   1361 
   1362 	/*
   1363 	 * Is there another message to obtain?
   1364 	 */
   1365 	if (mlx->mlx_lastevent != mlx->mlx_currevent)
   1366 		mlx_periodic_eventlog_poll(mlx);
   1367 	else
   1368 		mlx->mlx_flags &= ~MLXF_EVENTLOG_BUSY;
   1369 }
   1370 
   1371 /*
   1372  * Handle check/rebuild operations in progress.
   1373  */
   1374 static void
   1375 mlx_periodic_rebuild(struct mlx_ccb *mc)
   1376 {
   1377 	struct mlx_softc *mlx;
   1378 	const char *opstr;
   1379 	struct mlx_rebuild_status *mr;
   1380 
   1381 	mlx = (struct mlx_softc *)mc->mc_mx.mx_dv;
   1382 	mr = mc->mc_mx.mx_context;
   1383 	mlx_ccb_unmap(mlx, mc);
   1384 
   1385 	switch (mc->mc_status) {
   1386 	case 0:
   1387 		/*
   1388 		 * Operation running, update stats.
   1389 		 */
   1390 		mlx->mlx_rebuildstat = *mr;
   1391 
   1392 		/* Spontaneous rebuild/check? */
   1393 		if (mlx->mlx_bg == 0) {
   1394 			mlx->mlx_bg = MLX_BG_SPONTANEOUS;
   1395 			printf("%s: background check/rebuild started\n",
   1396 			    mlx->mlx_dv.dv_xname);
   1397 		}
   1398 		break;
   1399 
   1400 	case 0x0105:
   1401 		/*
   1402 		 * Nothing running, finalise stats and report.
   1403 		 */
   1404 		switch (mlx->mlx_bg) {
   1405 		case MLX_BG_CHECK:
   1406 			/* XXX Print drive? */
   1407 			opstr = "consistency check";
   1408 			break;
   1409 
   1410 		case MLX_BG_REBUILD:
   1411 			/* XXX Print channel:target? */
   1412 			opstr = "drive rebuild";
   1413 			break;
   1414 
   1415 		case MLX_BG_SPONTANEOUS:
   1416 		default:
   1417 			/*
   1418 			 * If we have previously been non-idle, report the
   1419 			 * transition
   1420 			 */
   1421 			if (mlx->mlx_rebuildstat.rs_code !=
   1422 			    MLX_REBUILDSTAT_IDLE)
   1423 				opstr = "background check/rebuild";
   1424 			else
   1425 				opstr = NULL;
   1426 		}
   1427 
   1428 		if (opstr != NULL)
   1429 			printf("%s: %s completed\n", mlx->mlx_dv.dv_xname,
   1430 			    opstr);
   1431 
   1432 		mlx->mlx_bg = 0;
   1433 		mlx->mlx_rebuildstat.rs_code = MLX_REBUILDSTAT_IDLE;
   1434 		break;
   1435 	}
   1436 
   1437 	free(mc->mc_mx.mx_context, M_DEVBUF);
   1438 	mlx_ccb_free(mlx, mc);
   1439 	mlx->mlx_flags &= ~MLXF_PERIODIC_REBUILD;
   1440 }
   1441 
   1442 /*
   1443  * It's time to perform a channel pause action for (mlx), either start or
   1444  * stop the pause.
   1445  */
   1446 static void
   1447 mlx_pause_action(struct mlx_softc *mlx)
   1448 {
   1449 	struct mlx_ccb *mc;
   1450 	int failsafe, i, cmd;
   1451 	time_t ct;
   1452 
   1453 	ct = mlx_curtime();
   1454 
   1455 	/* What are we doing here? */
   1456 	if (mlx->mlx_pause.mp_when == 0) {
   1457 		cmd = MLX_CMD_STARTCHANNEL;
   1458 		failsafe = 0;
   1459 	} else {
   1460 		cmd = MLX_CMD_STOPCHANNEL;
   1461 
   1462 		/*
   1463 		 * Channels will always start again after the failsafe
   1464 		 * period, which is specified in multiples of 30 seconds.
   1465 		 * This constrains us to a maximum pause of 450 seconds.
   1466 		 */
   1467 		failsafe = ((mlx->mlx_pause.mp_howlong - ct) + 5) / 30;
   1468 
   1469 		if (failsafe > 0xf) {
   1470 			failsafe = 0xf;
   1471 			mlx->mlx_pause.mp_howlong = ct + (0xf * 30) - 5;
   1472 		}
   1473 	}
   1474 
   1475 	/* Build commands for every channel requested. */
   1476 	for (i = 0; i < mlx->mlx_enq2->me_actual_channels; i++) {
   1477 		if ((1 << i) & mlx->mlx_pause.mp_which) {
   1478 			if (mlx_ccb_alloc(mlx, &mc, 1) != 0) {
   1479 				printf("%s: %s failed for channel %d\n",
   1480 				    mlx->mlx_dv.dv_xname,
   1481 				    cmd == MLX_CMD_STOPCHANNEL ?
   1482 				    "pause" : "resume", i);
   1483 				continue;
   1484 			}
   1485 
   1486 			/* Build the command. */
   1487 			mlx_make_type2(mc, cmd, (failsafe << 4) | i, 0, 0,
   1488 			    0, 0, 0, 0, 0);
   1489 			mc->mc_mx.mx_handler = mlx_pause_done;
   1490 			mc->mc_mx.mx_dv = &mlx->mlx_dv;
   1491 
   1492 			mlx_ccb_enqueue(mlx, mc);
   1493 		}
   1494 	}
   1495 }
   1496 
   1497 static void
   1498 mlx_pause_done(struct mlx_ccb *mc)
   1499 {
   1500 	struct mlx_softc *mlx;
   1501 	int command, channel;
   1502 
   1503 	mlx = (struct mlx_softc *)mc->mc_mx.mx_dv;
   1504 	command = mc->mc_mbox[0];
   1505 	channel = mc->mc_mbox[2] & 0xf;
   1506 
   1507 	if (mc->mc_status != 0)
   1508 		printf("%s: %s command failed - %s\n", mlx->mlx_dv.dv_xname,
   1509 		    command == MLX_CMD_STOPCHANNEL ? "pause" : "resume",
   1510 		    mlx_ccb_diagnose(mc));
   1511 	else if (command == MLX_CMD_STOPCHANNEL)
   1512 		printf("%s: channel %d pausing for %ld seconds\n",
   1513 		    mlx->mlx_dv.dv_xname, channel,
   1514 		    (long)(mlx->mlx_pause.mp_howlong - mlx_curtime()));
   1515 	else
   1516 		printf("%s: channel %d resuming\n", mlx->mlx_dv.dv_xname,
   1517 		    channel);
   1518 
   1519 	mlx_ccb_free(mlx, mc);
   1520 }
   1521 
   1522 /*
   1523  * Perform an Enquiry command using a type-3 command buffer and a return a
   1524  * single linear result buffer.  If the completion function is specified, it
   1525  * will be called with the completed command (and the result response will
   1526  * not be valid until that point).  Otherwise, the command will either be
   1527  * busy-waited for (interrupts must be blocked), or slept for.
   1528  */
   1529 static void *
   1530 mlx_enquire(struct mlx_softc *mlx, int command, size_t bufsize,
   1531 	    void (*handler)(struct mlx_ccb *mc), int waitok)
   1532 {
   1533 	struct mlx_ccb *mc;
   1534 	void *result;
   1535 	int rv, mapped;
   1536 
   1537 	result = NULL;
   1538 	mapped = 0;
   1539 
   1540 	if ((rv = mlx_ccb_alloc(mlx, &mc, 1)) != 0)
   1541 		goto out;
   1542 
   1543 	result = malloc(bufsize, M_DEVBUF, waitok ? M_WAITOK : M_NOWAIT);
   1544 	if (result == NULL) {
   1545 		printf("mlx_enquire: malloc() failed\n");
   1546 		goto out;
   1547 	}
   1548 	if ((rv = mlx_ccb_map(mlx, mc, result, bufsize, MC_XFER_IN)) != 0)
   1549 		goto out;
   1550 	mapped = 1;
   1551 	if (mc->mc_nsgent != 1) {
   1552 		printf("mlx_enquire: too many segs\n");
   1553 		goto out;
   1554 	}
   1555 
   1556 	/* Build an enquiry command. */
   1557 	mlx_make_type2(mc, command, 0, 0, 0, 0, 0, 0, mc->mc_xfer_phys, 0);
   1558 
   1559 	/* Do we want a completion callback? */
   1560 	if (handler != NULL) {
   1561 		mc->mc_mx.mx_context = result;
   1562 		mc->mc_mx.mx_dv = &mlx->mlx_dv;
   1563 		mc->mc_mx.mx_handler = handler;
   1564 		mlx_ccb_enqueue(mlx, mc);
   1565 	} else {
   1566 		/* Run the command in either polled or wait mode. */
   1567 		if (waitok)
   1568 			rv = mlx_ccb_wait(mlx, mc);
   1569 		else
   1570 			rv = mlx_ccb_poll(mlx, mc, 5000);
   1571 	}
   1572 
   1573  out:
   1574 	/* We got a command, but nobody else will free it. */
   1575 	if (handler == NULL && mc != NULL) {
   1576 		if (mapped)
   1577 			mlx_ccb_unmap(mlx, mc);
   1578 		mlx_ccb_free(mlx, mc);
   1579 	}
   1580 
   1581 	/* We got an error, and we allocated a result. */
   1582 	if (rv != 0 && result != NULL) {
   1583 		if (handler != NULL && mc != NULL) {
   1584 			if (mapped)
   1585 				mlx_ccb_unmap(mlx, mc);
   1586 			mlx_ccb_free(mlx, mc);
   1587 		}
   1588 		free(result, M_DEVBUF);
   1589 		result = NULL;
   1590 	}
   1591 
   1592 	return (result);
   1593 }
   1594 
   1595 /*
   1596  * Perform a Flush command on the nominated controller.
   1597  *
   1598  * May be called with interrupts enabled or disabled; will not return until
   1599  * the flush operation completes or fails.
   1600  */
   1601 int
   1602 mlx_flush(struct mlx_softc *mlx, int async)
   1603 {
   1604 	struct mlx_ccb *mc;
   1605 	int rv;
   1606 
   1607 	if ((rv = mlx_ccb_alloc(mlx, &mc, 1)) != 0)
   1608 		goto out;
   1609 
   1610 	/* Build a flush command and fire it off. */
   1611 	mlx_make_type2(mc, MLX_CMD_FLUSH, 0, 0, 0, 0, 0, 0, 0, 0);
   1612 
   1613 	if (async)
   1614 		rv = mlx_ccb_wait(mlx, mc);
   1615 	else
   1616 		rv = mlx_ccb_poll(mlx, mc, MLX_TIMEOUT * 1000);
   1617 	if (rv != 0)
   1618 		goto out;
   1619 
   1620 	/* Command completed OK? */
   1621 	if (mc->mc_status != 0) {
   1622 		printf("%s: FLUSH failed - %s\n", mlx->mlx_dv.dv_xname,
   1623 		    mlx_ccb_diagnose(mc));
   1624 		rv = EIO;
   1625 	}
   1626  out:
   1627 	if (mc != NULL)
   1628 		mlx_ccb_free(mlx, mc);
   1629 
   1630 	return (rv);
   1631 }
   1632 
   1633 /*
   1634  * Start a background consistency check on (drive).
   1635  */
   1636 static int
   1637 mlx_check(struct mlx_softc *mlx, int drive)
   1638 {
   1639 	struct mlx_ccb *mc;
   1640 	int rv;
   1641 
   1642 	/* Get ourselves a command buffer. */
   1643 	rv = 0x10000;
   1644 
   1645 	if (mlx_ccb_alloc(mlx, &mc, 1) != 0)
   1646 		goto out;
   1647 
   1648 	/* Build a checkasync command, set the "fix it" flag. */
   1649 	mlx_make_type2(mc, MLX_CMD_CHECKASYNC, 0, 0, 0, 0, 0, drive | 0x80,
   1650 	    0, 0);
   1651 
   1652 	/* Start the command and wait for it to be returned. */
   1653 	if (mlx_ccb_wait(mlx, mc) != 0)
   1654 		goto out;
   1655 
   1656 	/* Command completed OK? */
   1657 	if (mc->mc_status != 0)
   1658 		printf("%s: CHECK ASYNC failed - %s\n", mlx->mlx_dv.dv_xname,
   1659 		    mlx_ccb_diagnose(mc));
   1660 	else
   1661 		printf("%s: consistency check started",
   1662 		    mlx->mlx_sysdrive[drive].ms_dv->dv_xname);
   1663 
   1664 	rv = mc->mc_status;
   1665  out:
   1666 	if (mc != NULL)
   1667 		mlx_ccb_free(mlx, mc);
   1668 
   1669 	return (rv);
   1670 }
   1671 
   1672 /*
   1673  * Start a background rebuild of the physical drive at (channel),(target).
   1674  *
   1675  * May be called with interrupts enabled or disabled; will return as soon as
   1676  * the operation has started or been refused.
   1677  */
   1678 static int
   1679 mlx_rebuild(struct mlx_softc *mlx, int channel, int target)
   1680 {
   1681 	struct mlx_ccb *mc;
   1682 	int error;
   1683 
   1684 	error = 0x10000;
   1685 	if (mlx_ccb_alloc(mlx, &mc, 1) != 0)
   1686 		goto out;
   1687 
   1688 	/* Build a rebuildasync command, set the "fix it" flag. */
   1689 	mlx_make_type2(mc, MLX_CMD_REBUILDASYNC, channel, target, 0, 0, 0, 0,
   1690 	    0, 0);
   1691 
   1692 	/* Start the command and wait for it to be returned. */
   1693 	if (mlx_ccb_wait(mlx, mc) != 0)
   1694 		goto out;
   1695 
   1696 	/* Command completed OK? */
   1697 	printf("%s: ", mlx->mlx_dv.dv_xname);
   1698 	if (mc->mc_status != 0)
   1699 		printf("REBUILD ASYNC failed - %s\n", mlx_ccb_diagnose(mc));
   1700 	else
   1701 		printf("rebuild started for %d:%d\n", channel, target);
   1702 
   1703 	error = mc->mc_status;
   1704 
   1705  out:
   1706 	if (mc != NULL)
   1707 		mlx_ccb_free(mlx, mc);
   1708 
   1709 	return (error);
   1710 }
   1711 
   1712 /*
   1713  * Take a command from user-space and try to run it.
   1714  *
   1715  * XXX Note that this can't perform very much in the way of error checking,
   1716  * XXX and as such, applications _must_ be considered trustworthy.
   1717  *
   1718  * XXX Commands using S/G for data are not supported.
   1719  */
   1720 static int
   1721 mlx_user_command(struct mlx_softc *mlx, struct mlx_usercommand *mu)
   1722 {
   1723 	struct mlx_ccb *mc;
   1724 	struct mlx_dcdb *dcdb;
   1725 	void *kbuf;
   1726 	int rv, mapped;
   1727 
   1728 	if ((mu->mu_bufdir & ~MU_XFER_MASK) != 0)
   1729 		return (EINVAL);
   1730 
   1731 	kbuf = NULL;
   1732 	dcdb = NULL;
   1733 	mapped = 0;
   1734 
   1735 	/* Get ourselves a command and copy in from user space. */
   1736 	if ((rv = mlx_ccb_alloc(mlx, &mc, 1)) != 0) {
   1737 		DPRINTF(("mlx_user_command: mlx_ccb_alloc = %d\n", rv));
   1738 		goto out;
   1739 	}
   1740 
   1741 	memcpy(mc->mc_mbox, mu->mu_command, sizeof(mc->mc_mbox));
   1742 
   1743 	/*
   1744 	 * If we need a buffer for data transfer, allocate one and copy in
   1745 	 * its initial contents.
   1746 	 */
   1747 	if (mu->mu_datasize > 0) {
   1748 		if (mu->mu_datasize > MAXPHYS)
   1749 			return (EINVAL);
   1750 
   1751 		kbuf = malloc(mu->mu_datasize, M_DEVBUF, M_WAITOK);
   1752 		if (kbuf == NULL) {
   1753 			DPRINTF(("mlx_user_command: malloc = NULL\n"));
   1754 			rv = ENOMEM;
   1755 			goto out;
   1756 		}
   1757 
   1758 		if ((mu->mu_bufdir & MU_XFER_OUT) != 0) {
   1759 			rv = copyin(mu->mu_buf, kbuf, mu->mu_datasize);
   1760 			if (rv != 0) {
   1761 				DPRINTF(("mlx_user_command: copyin = %d\n",
   1762 				    rv));
   1763 				goto out;
   1764 			}
   1765 		}
   1766 
   1767 		/* Map the buffer so the controller can see it. */
   1768 		rv = mlx_ccb_map(mlx, mc, kbuf, mu->mu_datasize, mu->mu_bufdir);
   1769 		if (rv != 0) {
   1770 			DPRINTF(("mlx_user_command: mlx_ccb_map = %d\n", rv));
   1771 			goto out;
   1772 		}
   1773 		if (mc->mc_nsgent > 1) {
   1774 			DPRINTF(("mlx_user_command: too many s/g entries\n"));
   1775 			rv = EFBIG;
   1776 			goto out;
   1777 		}
   1778 		mapped = 1;
   1779 	}
   1780 
   1781 	/*
   1782 	 * If this is a passthrough SCSI command, the DCDB is packed at the
   1783 	 * beginning of the data area.  Fix up the DCDB to point to the correct physical
   1784 	 * address and override any bufptr supplied by the caller since we know
   1785 	 * what it's meant to be.
   1786 	 */
   1787 	if (mc->mc_mbox[0] == MLX_CMD_DIRECT_CDB) {
   1788 		dcdb = (struct mlx_dcdb *)kbuf;
   1789 		dcdb->dcdb_physaddr = mc->mc_xfer_phys + sizeof(*dcdb);
   1790 		mu->mu_bufptr = 8;
   1791 	}
   1792 
   1793 	/*
   1794 	 * If there's a data buffer, fix up the command's buffer pointer.
   1795 	 */
   1796 	if (mu->mu_datasize > 0) {
   1797 		/* Range check the pointer to physical buffer address. */
   1798 		if (mu->mu_bufptr < 0 ||
   1799 		    mu->mu_bufptr > sizeof(mu->mu_command) - 4) {
   1800 			DPRINTF(("mlx_user_command: bufptr botch\n"));
   1801 			rv = EINVAL;
   1802 			goto out;
   1803 		}
   1804 
   1805 		mc->mc_mbox[mu->mu_bufptr] = mc->mc_xfer_phys;
   1806 		mc->mc_mbox[mu->mu_bufptr+1] = mc->mc_xfer_phys >> 8;
   1807 		mc->mc_mbox[mu->mu_bufptr+2] = mc->mc_xfer_phys >> 16;
   1808 		mc->mc_mbox[mu->mu_bufptr+3] = mc->mc_xfer_phys >> 24;
   1809 	}
   1810 
   1811 	/* Submit the command and wait. */
   1812 	if ((rv = mlx_ccb_wait(mlx, mc)) != 0) {
   1813 #ifdef DEBUG
   1814 		printf("mlx_user_command: mlx_ccb_wait = %d\n", rv);
   1815 #endif
   1816 	}
   1817 
   1818  out:
   1819 	if (mc != NULL) {
   1820 		if (mapped)
   1821 			mlx_ccb_unmap(mlx, mc);
   1822 		mlx_ccb_free(mlx, mc);
   1823 	}
   1824 
   1825 	/* Copy out status and data */
   1826 	mu->mu_status = mc->mc_status;
   1827 
   1828 	if (kbuf != NULL) {
   1829 		if (mu->mu_datasize > 0 && (mu->mu_bufdir & MU_XFER_IN) != 0) {
   1830 			rv = copyout(kbuf, mu->mu_buf, mu->mu_datasize);
   1831 #ifdef DIAGNOSTIC
   1832 			if (rv != 0)
   1833 				printf("mlx_user_command: copyout = %d\n", rv);
   1834 #endif
   1835 		}
   1836 	}
   1837 	if (kbuf != NULL)
   1838 		free(kbuf, M_DEVBUF);
   1839 
   1840 	return (rv);
   1841 }
   1842 
   1843 /*
   1844  * Allocate and initialise a CCB.
   1845  */
   1846 int
   1847 mlx_ccb_alloc(struct mlx_softc *mlx, struct mlx_ccb **mcp, int special)
   1848 {
   1849 	struct mlx_ccb *mc;
   1850 	int s;
   1851 
   1852 	s = splbio();
   1853 	if ((!special && mlx->mlx_nccbs_free < MLX_NCCBS_RESERVE) ||
   1854 	    SLIST_FIRST(&mlx->mlx_ccb_freelist) == NULL) {
   1855 		splx(s);
   1856 		*mcp = NULL;
   1857 		return (EAGAIN);
   1858 	}
   1859 	mc = SLIST_FIRST(&mlx->mlx_ccb_freelist);
   1860 	SLIST_REMOVE_HEAD(&mlx->mlx_ccb_freelist, mc_chain.slist);
   1861 	mlx->mlx_nccbs_free--;
   1862 	splx(s);
   1863 
   1864 	*mcp = mc;
   1865 	return (0);
   1866 }
   1867 
   1868 /*
   1869  * Free a CCB.
   1870  */
   1871 void
   1872 mlx_ccb_free(struct mlx_softc *mlx, struct mlx_ccb *mc)
   1873 {
   1874 	int s;
   1875 
   1876 	s = splbio();
   1877 	mc->mc_flags = 0;
   1878 	SLIST_INSERT_HEAD(&mlx->mlx_ccb_freelist, mc, mc_chain.slist);
   1879 	mlx->mlx_nccbs_free++;
   1880 	splx(s);
   1881 }
   1882 
   1883 /*
   1884  * If a CCB is specified, enqueue it.  Pull CCBs off the software queue in
   1885  * the order that they were enqueued and try to submit their mailboxes to
   1886  * the controller for execution.
   1887  */
   1888 void
   1889 mlx_ccb_enqueue(struct mlx_softc *mlx, struct mlx_ccb *mc)
   1890 {
   1891 	int s;
   1892 
   1893 	s = splbio();
   1894 
   1895 	if (mc != NULL)
   1896 		SIMPLEQ_INSERT_TAIL(&mlx->mlx_ccb_queue, mc, mc_chain.simpleq);
   1897 
   1898 	while ((mc = SIMPLEQ_FIRST(&mlx->mlx_ccb_queue)) != NULL) {
   1899 		if (mlx_ccb_submit(mlx, mc) != 0)
   1900 			break;
   1901 		SIMPLEQ_REMOVE_HEAD(&mlx->mlx_ccb_queue, mc, mc_chain.simpleq);
   1902 		TAILQ_INSERT_TAIL(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq);
   1903 	}
   1904 
   1905 	splx(s);
   1906 }
   1907 
   1908 /*
   1909  * Map the specified CCB's data buffer onto the bus, and fill the
   1910  * scatter-gather list.
   1911  */
   1912 int
   1913 mlx_ccb_map(struct mlx_softc *mlx, struct mlx_ccb *mc, void *data, int size,
   1914 	    int dir)
   1915 {
   1916 	struct mlx_sgentry *sge;
   1917 	int nsegs, i, rv, sgloff;
   1918 	bus_dmamap_t xfer;
   1919 
   1920 	xfer = mc->mc_xfer_map;
   1921 
   1922 	rv = bus_dmamap_load(mlx->mlx_dmat, xfer, data, size, NULL,
   1923 	    BUS_DMA_NOWAIT | BUS_DMA_STREAMING |
   1924 	    ((dir & MC_XFER_IN) ? BUS_DMA_READ : BUS_DMA_WRITE));
   1925 	if (rv != 0)
   1926 		return (rv);
   1927 
   1928 	nsegs = xfer->dm_nsegs;
   1929 	mc->mc_xfer_size = size;
   1930 	mc->mc_flags |= dir;
   1931 	mc->mc_nsgent = nsegs;
   1932 	mc->mc_xfer_phys = xfer->dm_segs[0].ds_addr;
   1933 
   1934 	sgloff = MLX_SGL_SIZE * mc->mc_ident;
   1935 	sge = (struct mlx_sgentry *)((caddr_t)mlx->mlx_sgls + sgloff);
   1936 
   1937 	for (i = 0; i < nsegs; i++, sge++) {
   1938 		sge->sge_addr = htole32(xfer->dm_segs[i].ds_addr);
   1939 		sge->sge_count = htole32(xfer->dm_segs[i].ds_len);
   1940 	}
   1941 
   1942 	if ((dir & MC_XFER_OUT) != 0)
   1943 		i = BUS_DMASYNC_PREWRITE;
   1944 	else
   1945 		i = 0;
   1946 	if ((dir & MC_XFER_IN) != 0)
   1947 		i |= BUS_DMASYNC_PREREAD;
   1948 
   1949 	bus_dmamap_sync(mlx->mlx_dmat, xfer, 0, mc->mc_xfer_size, i);
   1950 	bus_dmamap_sync(mlx->mlx_dmat, mlx->mlx_dmamap, sgloff,
   1951 	    MLX_SGL_SIZE, BUS_DMASYNC_PREWRITE);
   1952 
   1953 	return (0);
   1954 }
   1955 
   1956 /*
   1957  * Unmap the specified CCB's data buffer.
   1958  */
   1959 void
   1960 mlx_ccb_unmap(struct mlx_softc *mlx, struct mlx_ccb *mc)
   1961 {
   1962 	int i;
   1963 
   1964 	bus_dmamap_sync(mlx->mlx_dmat, mlx->mlx_dmamap,
   1965 	    MLX_SGL_SIZE * mc->mc_ident, MLX_SGL_SIZE,
   1966 	    BUS_DMASYNC_POSTWRITE);
   1967 
   1968 	if ((mc->mc_flags & MC_XFER_OUT) != 0)
   1969 		i = BUS_DMASYNC_POSTWRITE;
   1970 	else
   1971 		i = 0;
   1972 	if ((mc->mc_flags & MC_XFER_IN) != 0)
   1973 		i |= BUS_DMASYNC_POSTREAD;
   1974 
   1975 	bus_dmamap_sync(mlx->mlx_dmat, mc->mc_xfer_map, 0, mc->mc_xfer_size, i);
   1976 	bus_dmamap_unload(mlx->mlx_dmat, mc->mc_xfer_map);
   1977 }
   1978 
   1979 /*
   1980  * Submit the CCB, and busy-wait for it to complete.  Return non-zero on
   1981  * timeout or submission error.  Must be called with interrupts blocked.
   1982  */
   1983 int
   1984 mlx_ccb_poll(struct mlx_softc *mlx, struct mlx_ccb *mc, int timo)
   1985 {
   1986 	int rv;
   1987 
   1988 	mc->mc_mx.mx_handler = NULL;
   1989 
   1990 	if ((rv = mlx_ccb_submit(mlx, mc)) != 0)
   1991 		return (rv);
   1992 	TAILQ_INSERT_TAIL(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq);
   1993 
   1994 	for (timo *= 10; timo != 0; timo--) {
   1995 		mlx_intr(mlx);
   1996 		if (mc->mc_status != MLX_STATUS_BUSY)
   1997 			break;
   1998 		DELAY(100);
   1999 	}
   2000 
   2001 	if (timo != 0) {
   2002 		if (mc->mc_status != 0) {
   2003 			printf("%s: command failed - %s\n",
   2004 			    mlx->mlx_dv.dv_xname, mlx_ccb_diagnose(mc));
   2005 			rv = EIO;
   2006 		} else
   2007 			rv = 0;
   2008 	} else {
   2009 		printf("%s: command timed out\n", mlx->mlx_dv.dv_xname);
   2010 		rv = EIO;
   2011 	}
   2012 
   2013 	return (rv);
   2014 }
   2015 
   2016 /*
   2017  * Enqueue the CCB, and sleep until it completes.  Return non-zero on
   2018  * timeout or error.
   2019  */
   2020 int
   2021 mlx_ccb_wait(struct mlx_softc *mlx, struct mlx_ccb *mc)
   2022 {
   2023 	int s;
   2024 
   2025 	mc->mc_flags |= MC_WAITING;
   2026 	mc->mc_mx.mx_handler = NULL;
   2027 
   2028 	s = splbio();
   2029 	mlx_ccb_enqueue(mlx, mc);
   2030 	tsleep(mc, PRIBIO, "mlxwccb", 0);
   2031 	splx(s);
   2032 
   2033 	if (mc->mc_status != 0) {
   2034 		printf("%s: command failed - %s\n", mlx->mlx_dv.dv_xname,
   2035 		    mlx_ccb_diagnose(mc));
   2036 		return (EIO);
   2037 	}
   2038 
   2039 	return (0);
   2040 }
   2041 
   2042 /*
   2043  * Try to submit a CCB's mailbox to the controller for execution.  Return
   2044  * non-zero on timeout or error.  Must be called with interrupts blocked.
   2045  */
   2046 static int
   2047 mlx_ccb_submit(struct mlx_softc *mlx, struct mlx_ccb *mc)
   2048 {
   2049 	int i, s, r;
   2050 
   2051 	/* Save the ident so we can handle this command when complete. */
   2052 	mc->mc_mbox[1] = (u_int8_t)mc->mc_ident;
   2053 
   2054 	/* Mark the command as currently being processed. */
   2055 	mc->mc_status = MLX_STATUS_BUSY;
   2056 	mc->mc_expiry = mlx_curtime() + MLX_TIMEOUT;
   2057 
   2058 	/* Spin waiting for the mailbox. */
   2059 	for (i = 100; i != 0; i--) {
   2060 		s = splbio();
   2061 		r = (*mlx->mlx_submit)(mlx, mc);
   2062 		splx(s);
   2063 		if (r != 0)
   2064 			break;
   2065 		DELAY(100);
   2066 	}
   2067 	if (i != 0)
   2068 		return (0);
   2069 
   2070 	DPRINTF(("mlx_ccb_submit: rejected; queueing\n"));
   2071 	mc->mc_status = MLX_STATUS_WEDGED;
   2072 	return (EIO);
   2073 }
   2074 
   2075 /*
   2076  * Return a string that describes why a command has failed.
   2077  */
   2078 const char *
   2079 mlx_ccb_diagnose(struct mlx_ccb *mc)
   2080 {
   2081 	static char buf[80];
   2082 	int i;
   2083 
   2084 	for (i = 0; i < sizeof(mlx_msgs) / sizeof(mlx_msgs[0]); i++)
   2085 		if ((mc->mc_mbox[0] == mlx_msgs[i].command ||
   2086 		    mlx_msgs[i].command == 0) &&
   2087 		    mc->mc_status == mlx_msgs[i].status) {
   2088 			sprintf(buf, "%s (0x%x)",
   2089 			    mlx_status_msgs[mlx_msgs[i].msg], mc->mc_status);
   2090 			return (buf);
   2091 		}
   2092 
   2093 	sprintf(buf, "unknown response 0x%x for command 0x%x",
   2094 	    (int)mc->mc_status, (int)mc->mc_mbox[0]);
   2095 
   2096 	return (buf);
   2097 }
   2098 
   2099 /*
   2100  * Poll the controller for completed commands.  Returns non-zero if one or
   2101  * more commands were completed.  Must be called with interrupts blocked.
   2102  */
   2103 int
   2104 mlx_intr(void *cookie)
   2105 {
   2106 	struct mlx_softc *mlx;
   2107 	struct mlx_ccb *mc;
   2108 	int result;
   2109 	u_int ident, status;
   2110 
   2111 	mlx = cookie;
   2112 	result = 0;
   2113 
   2114 	while ((*mlx->mlx_findcomplete)(mlx, &ident, &status) != 0) {
   2115 		result = 1;
   2116 
   2117 		if (ident >= MLX_MAX_QUEUECNT) {
   2118 			printf("%s: bad completion returned\n",
   2119 			    mlx->mlx_dv.dv_xname);
   2120 			continue;
   2121 		}
   2122 
   2123 		mc = mlx->mlx_ccbs + ident;
   2124 
   2125 		if (mc->mc_status != MLX_STATUS_BUSY) {
   2126 			printf("%s: bad completion returned\n",
   2127 			    mlx->mlx_dv.dv_xname);
   2128 			continue;
   2129 		}
   2130 
   2131 		TAILQ_REMOVE(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq);
   2132 
   2133 		/* Record status and notify the initiator, if requested. */
   2134 		mc->mc_status = status;
   2135 		if (mc->mc_mx.mx_handler != NULL)
   2136 			(*mc->mc_mx.mx_handler)(mc);
   2137 		else if ((mc->mc_flags & MC_WAITING) != 0)
   2138 			wakeup(mc);
   2139 	}
   2140 
   2141 	/* If we've completed any commands, try posting some more. */
   2142 	if (result)
   2143 		mlx_ccb_enqueue(mlx, NULL);
   2144 
   2145 	return (result);
   2146 }
   2147 
   2148 /*
   2149  * Emit a string describing the firmware handshake status code, and return a
   2150  * flag indicating whether the code represents a fatal error.
   2151  *
   2152  * Error code interpretations are from the Linux driver, and don't directly
   2153  * match the messages printed by Mylex's BIOS.  This may change if
   2154  * documentation on the codes is forthcoming.
   2155  */
   2156 static int
   2157 mlx_fw_message(struct mlx_softc *mlx, int error, int param1, int param2)
   2158 {
   2159 	const char *fmt;
   2160 
   2161 	switch (error) {
   2162 	case 0x00:
   2163 		fmt = "physical drive %d:%d not responding";
   2164 		break;
   2165 
   2166 	case 0x08:
   2167 		/*
   2168 		 * We could be neater about this and give some indication
   2169 		 * when we receive more of them.
   2170 		 */
   2171 		if ((mlx->mlx_flags & MLXF_SPINUP_REPORTED) == 0) {
   2172 			printf("%s: spinning up drives...\n",
   2173 			    mlx->mlx_dv.dv_xname);
   2174 			mlx->mlx_flags |= MLXF_SPINUP_REPORTED;
   2175 		}
   2176 		break;
   2177 
   2178 	case 0x30:
   2179 		fmt = "configuration checksum error";
   2180 		break;
   2181 
   2182 	case 0x60:
   2183 		fmt = "mirror race recovery failed";
   2184 		break;
   2185 
   2186 	case 0x70:
   2187 		fmt = "mirror race recovery in progress";
   2188 		break;
   2189 
   2190 	case 0x90:
   2191 		fmt = "physical drive %d:%d COD mismatch";
   2192 		break;
   2193 
   2194 	case 0xa0:
   2195 		fmt = "logical drive installation aborted";
   2196 		break;
   2197 
   2198 	case 0xb0:
   2199 		fmt = "mirror race on a critical system drive";
   2200 		break;
   2201 
   2202 	case 0xd0:
   2203 		fmt = "new controller configuration found";
   2204 		break;
   2205 
   2206 	case 0xf0:
   2207 		fmt = "FATAL MEMORY PARITY ERROR";
   2208 		return (1);
   2209 
   2210 	default:
   2211 		printf("%s: unknown firmware init error %02x:%02x:%02x\n",
   2212 		    mlx->mlx_dv.dv_xname, error, param1, param2);
   2213 		return (0);
   2214 	}
   2215 
   2216 	printf("%s: ", mlx->mlx_dv.dv_xname);
   2217 	printf(fmt, param2, param1);
   2218 	printf("\n");
   2219 
   2220 	return (0);
   2221 }
   2222