mlx.c revision 58345
1/*-
2 * Copyright (c) 1999 Michael Smith
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 *	$FreeBSD: head/sys/dev/mlx/mlx.c 58345 2000-03-20 10:44:49Z phk $
27 */
28
29/*
30 * Driver for the Mylex DAC960 family of RAID controllers.
31 */
32
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/malloc.h>
36#include <sys/kernel.h>
37
38#include <sys/buf.h>
39#include <sys/bus.h>
40#include <sys/conf.h>
41#include <sys/devicestat.h>
42#include <sys/disk.h>
43#include <sys/stat.h>
44
45#include <machine/resource.h>
46#include <machine/bus.h>
47#include <machine/clock.h>
48#include <sys/rman.h>
49
50#include <dev/mlx/mlxio.h>
51#include <dev/mlx/mlxvar.h>
52#include <dev/mlx/mlxreg.h>
53
54#define MLX_CDEV_MAJOR	130
55
56static struct cdevsw mlx_cdevsw = {
57		/* open */	mlx_open,
58		/* close */	mlx_close,
59		/* read */	noread,
60		/* write */	nowrite,
61		/* ioctl */	mlx_ioctl,
62		/* poll */	nopoll,
63		/* mmap */	nommap,
64		/* strategy */	nostrategy,
65		/* name */ 	"mlx",
66		/* maj */	MLX_CDEV_MAJOR,
67		/* dump */	nodump,
68		/* psize */ 	nopsize,
69		/* flags */	0,
70		/* bmaj */	-1
71};
72
73devclass_t	mlx_devclass;
74
75/*
76 * Per-interface accessor methods
77 */
78static int			mlx_v3_tryqueue(struct mlx_softc *sc, struct mlx_command *mc);
79static int			mlx_v3_findcomplete(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status);
80static void			mlx_v3_intaction(struct mlx_softc *sc, int action);
81static int			mlx_v3_fw_handshake(struct mlx_softc *sc, int *error, int *param1, int *param2);
82
83static int			mlx_v4_tryqueue(struct mlx_softc *sc, struct mlx_command *mc);
84static int			mlx_v4_findcomplete(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status);
85static void			mlx_v4_intaction(struct mlx_softc *sc, int action);
86static int			mlx_v4_fw_handshake(struct mlx_softc *sc, int *error, int *param1, int *param2);
87
88static int			mlx_v5_tryqueue(struct mlx_softc *sc, struct mlx_command *mc);
89static int			mlx_v5_findcomplete(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status);
90static void			mlx_v5_intaction(struct mlx_softc *sc, int action);
91static int			mlx_v5_fw_handshake(struct mlx_softc *sc, int *error, int *param1, int *param2);
92
93/*
94 * Status monitoring
95 */
96static void			mlx_periodic(void *data);
97static void			mlx_periodic_enquiry(struct mlx_command *mc);
98static void			mlx_periodic_eventlog_poll(struct mlx_softc *sc);
99static void			mlx_periodic_eventlog_respond(struct mlx_command *mc);
100static void			mlx_periodic_rebuild(struct mlx_command *mc);
101
102/*
103 * Channel Pause
104 */
105static void			mlx_pause_action(struct mlx_softc *sc);
106static void			mlx_pause_done(struct mlx_command *mc);
107
108/*
109 * Command submission.
110 */
111static void			*mlx_enquire(struct mlx_softc *sc, int command, size_t bufsize,
112					     void (*complete)(struct mlx_command *mc));
113static int			mlx_flush(struct mlx_softc *sc);
114static int			mlx_rebuild(struct mlx_softc *sc, int channel, int target);
115static int			mlx_wait_command(struct mlx_command *mc);
116static int			mlx_poll_command(struct mlx_command *mc);
117static void			mlx_startio(struct mlx_softc *sc);
118static void			mlx_completeio(struct mlx_command *mc);
119static int			mlx_user_command(struct mlx_softc *sc, struct mlx_usercommand *mu);
120
121/*
122 * Command buffer allocation.
123 */
124static struct mlx_command	*mlx_alloccmd(struct mlx_softc *sc);
125static void			mlx_releasecmd(struct mlx_command *mc);
126static void			mlx_freecmd(struct mlx_command *mc);
127
128/*
129 * Command management.
130 */
131static int			mlx_getslot(struct mlx_command *mc);
132static void			mlx_mapcmd(struct mlx_command *mc);
133static void			mlx_unmapcmd(struct mlx_command *mc);
134static int			mlx_start(struct mlx_command *mc);
135static int			mlx_done(struct mlx_softc *sc);
136static void			mlx_complete(struct mlx_softc *sc);
137
138/*
139 * Debugging.
140 */
141static char			*mlx_diagnose_command(struct mlx_command *mc);
142static void			mlx_describe_controller(struct mlx_softc *sc);
143static int			mlx_fw_message(struct mlx_softc *sc, int status, int param1, int param2);
144
145/*
146 * Utility functions.
147 */
148static struct mlx_sysdrive	*mlx_findunit(struct mlx_softc *sc, int unit);
149
150/********************************************************************************
151 ********************************************************************************
152                                                                Public Interfaces
153 ********************************************************************************
154 ********************************************************************************/
155
156/********************************************************************************
157 * Free all of the resources associated with (sc)
158 *
159 * Should not be called if the controller is active.
160 */
161void
162mlx_free(struct mlx_softc *sc)
163{
164    struct mlx_command	*mc;
165
166    debug_called(1);
167
168    /* cancel status timeout */
169    untimeout(mlx_periodic, sc, sc->mlx_timeout);
170
171    /* throw away any command buffers */
172    while ((mc = TAILQ_FIRST(&sc->mlx_freecmds)) != NULL) {
173	TAILQ_REMOVE(&sc->mlx_freecmds, mc, mc_link);
174	mlx_freecmd(mc);
175    }
176
177    /* destroy data-transfer DMA tag */
178    if (sc->mlx_buffer_dmat)
179	bus_dma_tag_destroy(sc->mlx_buffer_dmat);
180
181    /* free and destroy DMA memory and tag for s/g lists */
182    if (sc->mlx_sgtable)
183	bus_dmamem_free(sc->mlx_sg_dmat, sc->mlx_sgtable, sc->mlx_sg_dmamap);
184    if (sc->mlx_sg_dmat)
185	bus_dma_tag_destroy(sc->mlx_sg_dmat);
186
187    /* disconnect the interrupt handler */
188    if (sc->mlx_intr)
189	bus_teardown_intr(sc->mlx_dev, sc->mlx_irq, sc->mlx_intr);
190    if (sc->mlx_irq != NULL)
191	bus_release_resource(sc->mlx_dev, SYS_RES_IRQ, 0, sc->mlx_irq);
192
193    /* destroy the parent DMA tag */
194    if (sc->mlx_parent_dmat)
195	bus_dma_tag_destroy(sc->mlx_parent_dmat);
196
197    /* release the register window mapping */
198    if (sc->mlx_mem != NULL)
199	bus_release_resource(sc->mlx_dev, SYS_RES_MEMORY,
200			     (sc->mlx_iftype == MLX_IFTYPE_3) ? MLX_CFG_BASE1 : MLX_CFG_BASE0, sc->mlx_mem);
201
202    /* free controller enquiry data */
203    if (sc->mlx_enq2 != NULL)
204	free(sc->mlx_enq2, M_DEVBUF);
205
206    /* destroy control device */
207    if (sc->mlx_dev_t != (dev_t)NULL)
208	destroy_dev(sc->mlx_dev_t);
209}
210
211/********************************************************************************
212 * Map the scatter/gather table into bus space
213 */
214static void
215mlx_dma_map_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
216{
217    struct mlx_softc	*sc = (struct mlx_softc *)arg;
218
219    debug_called(1);
220
221    /* save base of s/g table's address in bus space */
222    sc->mlx_sgbusaddr = segs->ds_addr;
223}
224
225static int
226mlx_sglist_map(struct mlx_softc *sc)
227{
228    size_t	segsize;
229    int		error;
230
231    debug_called(1);
232
233    /* destroy any existing mappings */
234    if (sc->mlx_sgtable)
235	bus_dmamem_free(sc->mlx_sg_dmat, sc->mlx_sgtable, sc->mlx_sg_dmamap);
236    if (sc->mlx_sg_dmat)
237	bus_dma_tag_destroy(sc->mlx_sg_dmat);
238
239    /*
240     * Create a single tag describing a region large enough to hold all of
241     * the s/g lists we will need.
242     */
243    segsize = sizeof(struct mlx_sgentry) * sc->mlx_sg_nseg * sc->mlx_maxiop;
244    error = bus_dma_tag_create(sc->mlx_parent_dmat, 	/* parent */
245			       1, 0, 			/* alignment, boundary */
246			       BUS_SPACE_MAXADDR,	/* lowaddr */
247			       BUS_SPACE_MAXADDR, 	/* highaddr */
248			       NULL, NULL, 		/* filter, filterarg */
249			       segsize, 1,		/* maxsize, nsegments */
250			       BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
251			       0,			/* flags */
252			       &sc->mlx_sg_dmat);
253    if (error != 0) {
254	device_printf(sc->mlx_dev, "can't allocate scatter/gather DMA tag\n");
255	return(ENOMEM);
256    }
257
258    /*
259     * Allocate enough s/g maps for all commands and permanently map them into
260     * controller-visible space.
261     *
262     * XXX this assumes we can get enough space for all the s/g maps in one
263     * contiguous slab.  We may need to switch to a more complex arrangement where
264     * we allocate in smaller chunks and keep a lookup table from slot to bus address.
265     */
266    error = bus_dmamem_alloc(sc->mlx_sg_dmat, (void **)&sc->mlx_sgtable, BUS_DMA_NOWAIT, &sc->mlx_sg_dmamap);
267    if (error) {
268	device_printf(sc->mlx_dev, "can't allocate s/g table\n");
269	return(ENOMEM);
270    }
271    bus_dmamap_load(sc->mlx_sg_dmat, sc->mlx_sg_dmamap, sc->mlx_sgtable, segsize, mlx_dma_map_sg, sc, 0);
272    return(0);
273}
274
275/********************************************************************************
276 * Initialise the controller and softc
277 */
278int
279mlx_attach(struct mlx_softc *sc)
280{
281    struct mlx_enquiry_old	*meo;
282    int				rid, error, fwminor, hscode, hserror, hsparam1, hsparam2, hsmsg;
283
284    debug_called(1);
285
286    /*
287     * Initialise per-controller queues.
288     */
289    TAILQ_INIT(&sc->mlx_work);
290    TAILQ_INIT(&sc->mlx_freecmds);
291    bufq_init(&sc->mlx_bufq);
292
293    /*
294     * Select accessor methods based on controller interface type.
295     */
296    switch(sc->mlx_iftype) {
297    case MLX_IFTYPE_2:
298    case MLX_IFTYPE_3:
299	sc->mlx_tryqueue	= mlx_v3_tryqueue;
300	sc->mlx_findcomplete	= mlx_v3_findcomplete;
301	sc->mlx_intaction	= mlx_v3_intaction;
302	sc->mlx_fw_handshake	= mlx_v3_fw_handshake;
303	sc->mlx_sg_nseg		= MLX_NSEG_OLD;
304	break;
305    case MLX_IFTYPE_4:
306	sc->mlx_tryqueue	= mlx_v4_tryqueue;
307	sc->mlx_findcomplete	= mlx_v4_findcomplete;
308	sc->mlx_intaction	= mlx_v4_intaction;
309	sc->mlx_fw_handshake	= mlx_v4_fw_handshake;
310	sc->mlx_sg_nseg		= MLX_NSEG_NEW;
311	break;
312    case MLX_IFTYPE_5:
313	sc->mlx_tryqueue	= mlx_v5_tryqueue;
314	sc->mlx_findcomplete	= mlx_v5_findcomplete;
315	sc->mlx_intaction	= mlx_v5_intaction;
316	sc->mlx_fw_handshake	= mlx_v5_fw_handshake;
317	sc->mlx_sg_nseg		= MLX_NSEG_NEW;
318	break;
319    default:
320	device_printf(sc->mlx_dev, "attaching unsupported interface version %d\n", sc->mlx_iftype);
321	return(ENXIO);		/* should never happen */
322    }
323
324    /* disable interrupts before we start talking to the controller */
325    sc->mlx_intaction(sc, MLX_INTACTION_DISABLE);
326
327    /*
328     * Wait for the controller to come ready, handshake with the firmware if required.
329     * This is typically only necessary on platforms where the controller BIOS does not
330     * run.
331     */
332    hsmsg = 0;
333    DELAY(1000);
334    while ((hscode = sc->mlx_fw_handshake(sc, &hserror, &hsparam1, &hsparam2)) != 0) {
335	/* report first time around... */
336	if (hsmsg == 0) {
337	    device_printf(sc->mlx_dev, "controller initialisation in progress...\n");
338	    hsmsg = 1;
339	}
340	/* did we get a real message? */
341	if (hscode == 2) {
342	    hscode = mlx_fw_message(sc, hserror, hsparam1, hsparam2);
343	    /* fatal initialisation error? */
344	    if (hscode != 0) {
345		mlx_free(sc);
346		return(ENXIO);
347	    }
348	}
349    }
350    if (hsmsg == 1)
351	device_printf(sc->mlx_dev, "initialisation complete.\n");
352
353    /*
354     * Allocate and connect our interrupt.
355     */
356    rid = 0;
357    sc->mlx_irq = bus_alloc_resource(sc->mlx_dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE);
358    if (sc->mlx_irq == NULL) {
359	device_printf(sc->mlx_dev, "couldn't allocate interrupt\n");
360	mlx_free(sc);
361	return(ENXIO);
362    }
363    error = bus_setup_intr(sc->mlx_dev, sc->mlx_irq, INTR_TYPE_BIO,  mlx_intr, sc, &sc->mlx_intr);
364    if (error) {
365	device_printf(sc->mlx_dev, "couldn't set up interrupt\n");
366	mlx_free(sc);
367	return(ENXIO);
368    }
369
370    /*
371     * Create DMA tag for mapping buffers into controller-addressable space.
372     */
373    error = bus_dma_tag_create(sc->mlx_parent_dmat, 		/* parent */
374			       1, 0, 				/* alignment, boundary */
375			       BUS_SPACE_MAXADDR,		/* lowaddr */
376			       BUS_SPACE_MAXADDR, 		/* highaddr */
377			       NULL, NULL, 			/* filter, filterarg */
378			       MAXBSIZE, sc->mlx_sg_nseg,	/* maxsize, nsegments */
379			       BUS_SPACE_MAXSIZE_32BIT,		/* maxsegsize */
380			       0,				/* flags */
381			       &sc->mlx_buffer_dmat);
382    if (error != 0) {
383	device_printf(sc->mlx_dev, "can't allocate buffer DMA tag\n");
384	return(ENOMEM);
385    }
386
387    /*
388     * Create an initial set of s/g mappings.
389     */
390    sc->mlx_maxiop = 8;
391    error = mlx_sglist_map(sc);
392    if (error != 0) {
393	device_printf(sc->mlx_dev, "couldn't make initial s/g list mapping\n");
394	return(error);
395    }
396
397    /* send an ENQUIRY2 to the controller */
398    if ((sc->mlx_enq2 = mlx_enquire(sc, MLX_CMD_ENQUIRY2, sizeof(struct mlx_enquiry2), NULL)) == NULL) {
399	device_printf(sc->mlx_dev, "ENQUIRY2 failed\n");
400	return(ENXIO);
401    }
402
403    /*
404     * We don't (yet) know where the event log is up to.
405     */
406    sc->mlx_lastevent = -1;
407
408    /*
409     * Do quirk/feature related things.
410     */
411    fwminor = (sc->mlx_enq2->me_firmware_id >> 8) & 0xff;
412    switch(sc->mlx_iftype) {
413    case MLX_IFTYPE_2:
414	/* These controllers don't report the firmware version in the ENQUIRY2 response */
415	if ((meo = mlx_enquire(sc, MLX_CMD_ENQUIRY_OLD, sizeof(struct mlx_enquiry_old), NULL)) == NULL) {
416	    device_printf(sc->mlx_dev, "ENQUIRY_OLD failed\n");
417	    return(ENXIO);
418	}
419	sc->mlx_enq2->me_firmware_id = ('0' << 24) | (0 << 16) | (meo->me_fwminor << 8) | meo->me_fwmajor;
420	free(meo, M_DEVBUF);
421
422	/* XXX require 2.42 or better (PCI) or 2.14 or better (EISA) */
423	if (meo->me_fwminor < 42) {
424	    device_printf(sc->mlx_dev, " *** WARNING *** This firmware revision is not recommended\n");
425	    device_printf(sc->mlx_dev, " *** WARNING *** Use revision 2.42 or later\n");
426	}
427	break;
428    case MLX_IFTYPE_3:
429	/* XXX certify 3.52? */
430	if (fwminor < 51) {
431	    device_printf(sc->mlx_dev, " *** WARNING *** This firmware revision is not recommended\n");
432	    device_printf(sc->mlx_dev, " *** WARNING *** Use revision 3.51 or later\n");
433	}
434	break;
435    case MLX_IFTYPE_4:
436	/* XXX certify firmware versions? */
437	if (fwminor < 6) {
438	    device_printf(sc->mlx_dev, " *** WARNING *** This firmware revision is not recommended\n");
439	    device_printf(sc->mlx_dev, " *** WARNING *** Use revision 4.06 or later\n");
440	}
441	break;
442    case MLX_IFTYPE_5:
443	if (fwminor < 7) {
444	    device_printf(sc->mlx_dev, " *** WARNING *** This firmware revision is not recommended\n");
445	    device_printf(sc->mlx_dev, " *** WARNING *** Use revision 5.07 or later\n");
446	}
447	break;
448    default:
449	device_printf(sc->mlx_dev, "interface version corrupted to %d\n", sc->mlx_iftype);
450	return(ENXIO);		/* should never happen */
451    }
452
453    /*
454     * Create the final set of s/g mappings now that we know how many commands
455     * the controller actually supports.
456     */
457    sc->mlx_maxiop = sc->mlx_enq2->me_max_commands;
458    error = mlx_sglist_map(sc);
459    if (error != 0) {
460	device_printf(sc->mlx_dev, "couldn't make initial s/g list mapping\n");
461	return(error);
462    }
463
464    /*
465     * No rebuild or check is in progress.
466     */
467    sc->mlx_rebuild = -1;
468    sc->mlx_check = -1;
469
470    /*
471     * Create the control device.
472     */
473    sc->mlx_dev_t = make_dev(&mlx_cdevsw, device_get_unit(sc->mlx_dev), UID_ROOT, GID_OPERATOR,
474			     S_IRUSR | S_IWUSR, "mlx%d", device_get_unit(sc->mlx_dev));
475
476    /*
477     * Start the timeout routine.
478     */
479    sc->mlx_timeout = timeout(mlx_periodic, sc, hz);
480
481    /* print a little information about the controller */
482    mlx_describe_controller(sc);
483
484    return(0);
485}
486
487/********************************************************************************
488 * Locate disk resources and attach children to them.
489 */
490void
491mlx_startup(struct mlx_softc *sc)
492{
493    struct mlx_enq_sys_drive	*mes;
494    struct mlx_sysdrive		*dr;
495    int				i, error;
496
497    debug_called(1);
498
499    /*
500     * Scan all the system drives and attach children for those that
501     * don't currently have them.
502     */
503    mes = mlx_enquire(sc, MLX_CMD_ENQSYSDRIVE, sizeof(*mes) * MLX_MAXDRIVES, NULL);
504    if (mes == NULL) {
505	device_printf(sc->mlx_dev, "error fetching drive status\n");
506	return;
507    }
508
509    /* iterate over drives returned */
510    for (i = 0, dr = &sc->mlx_sysdrive[0];
511	 (i < MLX_MAXDRIVES) && (mes[i].sd_size != 0xffffffff);
512	 i++, dr++) {
513	/* are we already attached to this drive? */
514    	if (dr->ms_disk == 0) {
515	    /* pick up drive information */
516	    dr->ms_size = mes[i].sd_size;
517	    dr->ms_raidlevel = mes[i].sd_raidlevel & 0xf;
518	    dr->ms_state = mes[i].sd_state;
519
520	    /* generate geometry information */
521	    if (sc->mlx_geom == MLX_GEOM_128_32) {
522		dr->ms_heads = 128;
523		dr->ms_sectors = 32;
524		dr->ms_cylinders = dr->ms_size / (128 * 32);
525	    } else {        /* MLX_GEOM_255/63 */
526		dr->ms_heads = 255;
527		dr->ms_sectors = 63;
528		dr->ms_cylinders = dr->ms_size / (255 * 63);
529	    }
530	    dr->ms_disk =  device_add_child(sc->mlx_dev, /*"mlxd"*/NULL, -1);
531	    if (dr->ms_disk == 0)
532		device_printf(sc->mlx_dev, "device_add_child failed\n");
533	    device_set_ivars(dr->ms_disk, dr);
534	}
535    }
536    free(mes, M_DEVBUF);
537    if ((error = bus_generic_attach(sc->mlx_dev)) != 0)
538	device_printf(sc->mlx_dev, "bus_generic_attach returned %d", error);
539
540    /* mark controller back up */
541    sc->mlx_state &= ~MLX_STATE_SHUTDOWN;
542
543    /* enable interrupts */
544    sc->mlx_intaction(sc, MLX_INTACTION_ENABLE);
545}
546
547/********************************************************************************
548 * Disconnect from the controller completely, in preparation for unload.
549 */
550int
551mlx_detach(device_t dev)
552{
553    struct mlx_softc	*sc = device_get_softc(dev);
554    struct mlxd_softc	*mlxd;
555    int			i, s, error;
556
557    debug_called(1);
558
559    error = EBUSY;
560    s = splbio();
561    if (sc->mlx_state & MLX_STATE_OPEN)
562	goto out;
563
564    for (i = 0; i < MLX_MAXDRIVES; i++) {
565	if (sc->mlx_sysdrive[i].ms_disk != 0) {
566	    mlxd = device_get_softc(sc->mlx_sysdrive[i].ms_disk);
567	    if (mlxd->mlxd_flags & MLXD_OPEN) {		/* drive is mounted, abort detach */
568		device_printf(sc->mlx_sysdrive[i].ms_disk, "still open, can't detach\n");
569		goto out;
570	    }
571	}
572    }
573    if ((error = mlx_shutdown(dev)))
574	goto out;
575
576    mlx_free(sc);
577
578    error = 0;
579 out:
580    splx(s);
581    return(error);
582}
583
584/********************************************************************************
585 * Bring the controller down to a dormant state and detach all child devices.
586 *
587 * This function is called before detach, system shutdown, or before performing
588 * an operation which may add or delete system disks.  (Call mlx_startup to
589 * resume normal operation.)
590 *
591 * Note that we can assume that the bufq on the controller is empty, as we won't
592 * allow shutdown if any device is open.
593 */
594int
595mlx_shutdown(device_t dev)
596{
597    struct mlx_softc	*sc = device_get_softc(dev);
598    int			i, s, error;
599
600    debug_called(1);
601
602    s = splbio();
603    error = 0;
604
605    sc->mlx_state |= MLX_STATE_SHUTDOWN;
606    sc->mlx_intaction(sc, MLX_INTACTION_DISABLE);
607
608    /* flush controller */
609    device_printf(sc->mlx_dev, "flushing cache...");
610    if (mlx_flush(sc)) {
611	printf("failed\n");
612    } else {
613	printf("done\n");
614    }
615
616    /* delete all our child devices */
617    for (i = 0; i < MLX_MAXDRIVES; i++) {
618	if (sc->mlx_sysdrive[i].ms_disk != 0) {
619	    if ((error = device_delete_child(sc->mlx_dev, sc->mlx_sysdrive[i].ms_disk)) != 0)
620		goto out;
621	    sc->mlx_sysdrive[i].ms_disk = 0;
622	}
623    }
624
625 out:
626    splx(s);
627    return(error);
628}
629
630/********************************************************************************
631 * Bring the controller to a quiescent state, ready for system suspend.
632 */
633int
634mlx_suspend(device_t dev)
635{
636    struct mlx_softc	*sc = device_get_softc(dev);
637    int			s;
638
639    debug_called(1);
640
641    s = splbio();
642    sc->mlx_state |= MLX_STATE_SUSPEND;
643
644    /* flush controller */
645    device_printf(sc->mlx_dev, "flushing cache...");
646    printf("%s\n", mlx_flush(sc) ? "failed" : "done");
647
648    sc->mlx_intaction(sc, MLX_INTACTION_DISABLE);
649    splx(s);
650
651    return(0);
652}
653
654/********************************************************************************
655 * Bring the controller back to a state ready for operation.
656 */
657int
658mlx_resume(device_t dev)
659{
660    struct mlx_softc	*sc = device_get_softc(dev);
661
662    debug_called(1);
663
664    sc->mlx_state &= ~MLX_STATE_SUSPEND;
665    sc->mlx_intaction(sc, MLX_INTACTION_ENABLE);
666
667    return(0);
668}
669
670/*******************************************************************************
671 * Take an interrupt, or be poked by other code to look for interrupt-worthy
672 * status.
673 */
674void
675mlx_intr(void *arg)
676{
677    struct mlx_softc	*sc = (struct mlx_softc *)arg;
678
679    debug_called(1);
680
681    /* collect finished commands, queue anything waiting */
682    mlx_done(sc);
683};
684
685/*******************************************************************************
686 * Receive a buf structure from a child device and queue it on a particular
687 * disk resource, then poke the disk resource to start as much work as it can.
688 */
689int
690mlx_submit_buf(struct mlx_softc *sc, struct buf *bp)
691{
692    int		s;
693
694    debug_called(1);
695
696    s = splbio();
697    bufq_insert_tail(&sc->mlx_bufq, bp);
698    sc->mlx_waitbufs++;
699    splx(s);
700    mlx_startio(sc);
701    return(0);
702}
703
704/********************************************************************************
705 * Accept an open operation on the control device.
706 */
707int
708mlx_open(dev_t dev, int flags, int fmt, struct proc *p)
709{
710    int			unit = minor(dev);
711    struct mlx_softc	*sc = devclass_get_softc(mlx_devclass, unit);
712
713    sc->mlx_state |= MLX_STATE_OPEN;
714    return(0);
715}
716
717/********************************************************************************
718 * Accept the last close on the control device.
719 */
720int
721mlx_close(dev_t dev, int flags, int fmt, struct proc *p)
722{
723    int			unit = minor(dev);
724    struct mlx_softc	*sc = devclass_get_softc(mlx_devclass, unit);
725
726    sc->mlx_state &= ~MLX_STATE_OPEN;
727    return (0);
728}
729
730/********************************************************************************
731 * Handle controller-specific control operations.
732 */
733int
734mlx_ioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p)
735{
736    int			unit = minor(dev);
737    struct mlx_softc	*sc = devclass_get_softc(mlx_devclass, unit);
738    int			*arg = (int *)addr;
739    struct mlx_pause	*mp;
740    struct mlx_sysdrive	*dr;
741    struct mlxd_softc	*mlxd;
742    int			i, error;
743
744    switch(cmd) {
745	/*
746	 * Enumerate connected system drives; returns the first system drive's
747	 * unit number if *arg is -1, or the next unit after *arg if it's
748	 * a valid unit on this controller.
749	 */
750    case MLX_NEXT_CHILD:
751	/* search system drives */
752	for (i = 0; i < MLX_MAXDRIVES; i++) {
753	    /* is this one attached? */
754	    if (sc->mlx_sysdrive[i].ms_disk != 0) {
755		/* looking for the next one we come across? */
756		if (*arg == -1) {
757		    *arg = device_get_unit(sc->mlx_sysdrive[i].ms_disk);
758		    return(0);
759		}
760		/* we want the one after this one */
761		if (*arg == device_get_unit(sc->mlx_sysdrive[i].ms_disk))
762		    *arg = -1;
763	    }
764	}
765	return(ENOENT);
766
767	/*
768	 * Scan the controller to see whether new drives have appeared.
769	 */
770    case MLX_RESCAN_DRIVES:
771	mlx_startup(sc);
772	return(0);
773
774	/*
775	 * Disconnect from the specified drive; it may be about to go
776	 * away.
777	 */
778    case MLX_DETACH_DRIVE:			/* detach one drive */
779
780	if (((dr = mlx_findunit(sc, *arg)) == NULL) ||
781	    ((mlxd = device_get_softc(dr->ms_disk)) == NULL))
782	    return(ENOENT);
783
784	device_printf(dr->ms_disk, "detaching...");
785	error = 0;
786	if (mlxd->mlxd_flags & MLXD_OPEN) {
787	    error = EBUSY;
788	    goto detach_out;
789	}
790
791	/* flush controller */
792	if (mlx_flush(sc)) {
793	    error = EBUSY;
794	    goto detach_out;
795	}
796
797	/* nuke drive */
798	if ((error = device_delete_child(sc->mlx_dev, dr->ms_disk)) != 0)
799	    goto detach_out;
800	dr->ms_disk = 0;
801
802    detach_out:
803	if (error) {
804	    printf("failed\n");
805	} else {
806	    printf("done\n");
807	}
808	return(error);
809
810	/*
811	 * Pause one or more SCSI channels for a period of time, to assist
812	 * in the process of hot-swapping devices.
813	 *
814	 * Note that at least the 3.51 firmware on the DAC960PL doesn't seem
815	 * to do this right.
816	 */
817    case MLX_PAUSE_CHANNEL:			/* schedule a channel pause */
818	/* Does this command work on this firmware? */
819	if (!(sc->mlx_feature & MLX_FEAT_PAUSEWORKS))
820	    return(EOPNOTSUPP);
821
822	mp = (struct mlx_pause *)addr;
823	if ((mp->mp_which == MLX_PAUSE_CANCEL) && (sc->mlx_pause.mp_when != 0)) {
824	    /* cancel a pending pause operation */
825	    sc->mlx_pause.mp_which = 0;
826	} else {
827	    /* fix for legal channels */
828	    mp->mp_which &= ((1 << sc->mlx_enq2->me_actual_channels) -1);
829	    /* check time values */
830	    if ((mp->mp_when < 0) || (mp->mp_when > 3600))
831		return(EINVAL);
832	    if ((mp->mp_howlong < 1) || (mp->mp_howlong > (0xf * 30)))
833		return(EINVAL);
834
835	    /* check for a pause currently running */
836	    if ((sc->mlx_pause.mp_which != 0) && (sc->mlx_pause.mp_when == 0))
837		return(EBUSY);
838
839	    /* looks ok, go with it */
840	    sc->mlx_pause.mp_which = mp->mp_which;
841	    sc->mlx_pause.mp_when = time_second + mp->mp_when;
842	    sc->mlx_pause.mp_howlong = sc->mlx_pause.mp_when + mp->mp_howlong;
843	}
844	return(0);
845
846	/*
847	 * Accept a command passthrough-style.
848	 */
849    case MLX_COMMAND:
850	return(mlx_user_command(sc, (struct mlx_usercommand *)addr));
851
852    default:
853	return(ENOTTY);
854    }
855}
856
857/********************************************************************************
858 * Handle operations requested by a System Drive connected to this controller.
859 */
860int
861mlx_submit_ioctl(struct mlx_softc *sc, struct mlx_sysdrive *drive, u_long cmd,
862		caddr_t addr, int32_t flag, struct proc *p)
863{
864    struct mlxd_rebuild		*mr = (struct mlxd_rebuild *)addr;
865    struct mlxd_rebuild_status	*mp = (struct mlxd_rebuild_status *)addr;
866    int				*arg = (int *)addr;
867    int				error;
868
869    switch(cmd) {
870	/*
871	 * Return the current status of this drive.
872	 */
873    case MLXD_STATUS:
874	*arg = drive->ms_state;
875	return(0);
876
877	/*
878	 * Start a background rebuild on this drive.
879	 */
880    case MLXD_REBUILDASYNC:
881	/* XXX lock? */
882	if (sc->mlx_rebuild >= 0)
883	    return(EBUSY);
884	sc->mlx_rebuild = drive - &sc->mlx_sysdrive[0];
885
886	switch (mlx_rebuild(sc, mr->rb_channel, mr->rb_target)) {
887	case 0:
888	    drive->ms_state = MLX_SYSD_REBUILD;
889	    error = 0;
890	    break;
891	case 0x10000:
892	    error = ENOMEM;		/* couldn't set up the command */
893	    break;
894	case 0x0002:
895	case 0x0106:
896	    error = EBUSY;
897	    break;
898	case 0x0004:
899	    error = EIO;
900	    break;
901	case 0x0105:
902	    error = ERANGE;
903	    break;
904	default:
905	    error = EINVAL;
906	    break;
907	}
908	if (error != 0)
909	    sc->mlx_rebuild = -1;
910	return(error);
911
912	/*
913	 * Start a background consistency check on this drive.
914	 */
915    case MLXD_CHECKASYNC:		/* start a background consistency check */
916	/* XXX implement */
917	break;
918
919	/*
920	 * Get the status of the current rebuild or consistency check.
921	 */
922    case MLXD_REBUILDSTAT:
923
924	if (sc->mlx_rebuild >= 0) {	/* may be a second or so out of date */
925	    mp->rs_drive = sc->mlx_rebuild;
926	    mp->rs_size = sc->mlx_sysdrive[sc->mlx_rebuild].ms_size;
927	    mp->rs_remaining = sc->mlx_rebuildstat;
928	    return(0);
929	} else if (sc->mlx_check >= 0) {
930	    /* XXX implement */
931	} else {
932	    /* XXX should return status of last completed operation? */
933	    return(EINVAL);
934	}
935
936    }
937    return(ENOIOCTL);
938}
939
940
941/********************************************************************************
942 ********************************************************************************
943                                                                Status Monitoring
944 ********************************************************************************
945 ********************************************************************************/
946
947/********************************************************************************
948 * Fire off commands to periodically check the status of connected drives.
949 */
950static void
951mlx_periodic(void *data)
952{
953    struct mlx_softc *sc = (struct mlx_softc *)data;
954
955    debug_called(1);
956
957    /*
958     * Run a bus pause?
959     */
960    if ((sc->mlx_pause.mp_which != 0) &&
961	(sc->mlx_pause.mp_when > 0) &&
962	(time_second >= sc->mlx_pause.mp_when)){
963
964	mlx_pause_action(sc);		/* pause is running */
965	sc->mlx_pause.mp_when = 0;
966	sysbeep(500, hz);
967
968	/*
969	 * Bus pause still running?
970	 */
971    } else if ((sc->mlx_pause.mp_which != 0) &&
972	       (sc->mlx_pause.mp_when == 0)) {
973
974	/* time to stop bus pause? */
975	if (time_second >= sc->mlx_pause.mp_howlong) {
976	    mlx_pause_action(sc);
977	    sc->mlx_pause.mp_which = 0;	/* pause is complete */
978	    sysbeep(500, hz);
979	} else {
980	    sysbeep((time_second % 5) * 100 + 500, hz/8);
981	}
982
983	/*
984	 * Run normal periodic activities?
985	 */
986    } else if (time_second > (sc->mlx_lastpoll + 10)) {
987	sc->mlx_lastpoll = time_second;
988
989	/*
990	 * Check controller status.
991	 *
992	 * XXX Note that this may not actually launch a command in situations of high load.
993	 */
994	mlx_enquire(sc, (sc->mlx_iftype == MLX_IFTYPE_2) ? MLX_CMD_ENQUIRY_OLD : MLX_CMD_ENQUIRY,
995		    imax(sizeof(struct mlx_enquiry), sizeof(struct mlx_enquiry_old)), mlx_periodic_enquiry);
996
997	/*
998	 * Check system drive status.
999	 *
1000	 * XXX This might be better left to event-driven detection, eg. I/O to an offline
1001	 *     drive will detect it's offline, rebuilds etc. should detect the drive is back
1002	 *     online.
1003	 */
1004	mlx_enquire(sc, MLX_CMD_ENQSYSDRIVE, sizeof(struct mlx_enq_sys_drive) * MLX_MAXDRIVES,
1005			mlx_periodic_enquiry);
1006
1007	/*
1008	 * Get drive rebuild/check status
1009	 */
1010	if (sc->mlx_rebuild >= 0)
1011	    mlx_enquire(sc, MLX_CMD_REBUILDSTAT, sizeof(struct mlx_rebuild_stat), mlx_periodic_rebuild);
1012    }
1013
1014    /* deal with possibly-missed interrupts and timed-out commands */
1015    mlx_done(sc);
1016
1017    /* reschedule another poll next second or so */
1018    sc->mlx_timeout = timeout(mlx_periodic, sc, hz);
1019}
1020
1021/********************************************************************************
1022 * Handle the result of an ENQUIRY command instigated by periodic status polling.
1023 */
1024static void
1025mlx_periodic_enquiry(struct mlx_command *mc)
1026{
1027    struct mlx_softc		*sc = mc->mc_sc;
1028
1029    debug_called(1);
1030
1031    /* Command completed OK? */
1032    if (mc->mc_status != 0) {
1033	device_printf(sc->mlx_dev, "periodic enquiry failed - %s\n", mlx_diagnose_command(mc));
1034	goto out;
1035    }
1036
1037    /* respond to command */
1038    switch(mc->mc_mailbox[0]) {
1039	/*
1040	 * This is currently a bit fruitless, as we don't know how to extract the eventlog
1041	 * pointer yet.
1042	 */
1043    case MLX_CMD_ENQUIRY_OLD:
1044    {
1045	struct mlx_enquiry		*me = (struct mlx_enquiry *)mc->mc_data;
1046	struct mlx_enquiry_old		*meo = (struct mlx_enquiry_old *)mc->mc_data;
1047	int				i;
1048
1049	/* convert data in-place to new format */
1050	for (i = (sizeof(me->me_dead) / sizeof(me->me_dead[0])) - 1; i >= 0; i--) {
1051	    me->me_dead[i].dd_chan = meo->me_dead[i].dd_chan;
1052	    me->me_dead[i].dd_targ = meo->me_dead[i].dd_targ;
1053	}
1054	me->me_misc_flags        = 0;
1055	me->me_rebuild_count     = meo->me_rebuild_count;
1056	me->me_dead_count        = meo->me_dead_count;
1057	me->me_critical_sd_count = meo->me_critical_sd_count;
1058	me->me_event_log_seq_num = 0;
1059	me->me_offline_sd_count  = meo->me_offline_sd_count;
1060	me->me_max_commands      = meo->me_max_commands;
1061	me->me_rebuild_flag      = meo->me_rebuild_flag;
1062	me->me_fwmajor           = meo->me_fwmajor;
1063	me->me_fwminor           = meo->me_fwminor;
1064	me->me_status_flags      = meo->me_status_flags;
1065	me->me_flash_age         = meo->me_flash_age;
1066	for (i = (sizeof(me->me_drvsize) / sizeof(me->me_drvsize[0])) - 1; i >= 0; i--) {
1067	    if (i > ((sizeof(meo->me_drvsize) / sizeof(meo->me_drvsize[0])) - 1)) {
1068		me->me_drvsize[i] = 0;		/* drive beyond supported range */
1069	    } else {
1070		me->me_drvsize[i] = meo->me_drvsize[i];
1071	    }
1072	}
1073	me->me_num_sys_drvs = meo->me_num_sys_drvs;
1074    }
1075    /* FALLTHROUGH */
1076
1077	/*
1078	 * Generic controller status update.  We could do more with this than just
1079	 * checking the event log.
1080	 */
1081    case MLX_CMD_ENQUIRY:
1082    {
1083	struct mlx_enquiry		*me = (struct mlx_enquiry *)mc->mc_data;
1084
1085	if (sc->mlx_lastevent == -1) {
1086	    /* initialise our view of the event log */
1087	    sc->mlx_currevent = sc->mlx_lastevent = me->me_event_log_seq_num;
1088	} else if (me->me_event_log_seq_num != sc->mlx_lastevent) {
1089	    /* record where current events are up to */
1090	    sc->mlx_currevent = me->me_event_log_seq_num;
1091	    debug(1, "event log pointer was %d, now %d\n", sc->mlx_lastevent, sc->mlx_currevent);
1092
1093	    /* drain new eventlog entries */
1094	    mlx_periodic_eventlog_poll(sc);
1095	}
1096	break;
1097    }
1098    case MLX_CMD_ENQSYSDRIVE:
1099    {
1100	struct mlx_enq_sys_drive	*mes = (struct mlx_enq_sys_drive *)mc->mc_data;
1101	struct mlx_sysdrive		*dr;
1102	int				i;
1103
1104	for (i = 0, dr = &sc->mlx_sysdrive[0];
1105	     (i < MLX_MAXDRIVES) && (mes[i].sd_size != 0xffffffff);
1106	     i++) {
1107
1108	    /* if disk is being rebuilt, we should not check it */
1109	    if (dr->ms_state == MLX_SYSD_REBUILD) {
1110		/* has state been changed by controller? */
1111		if (dr->ms_state != mes[i].sd_state) {
1112		    switch(mes[i].sd_state) {
1113		    case MLX_SYSD_OFFLINE:
1114			device_printf(dr->ms_disk, "drive offline\n");
1115			break;
1116		    case MLX_SYSD_ONLINE:
1117			device_printf(dr->ms_disk, "drive online\n");
1118			break;
1119		    case MLX_SYSD_CRITICAL:
1120			device_printf(dr->ms_disk, "drive critical\n");
1121			break;
1122		    }
1123		    /* save new state */
1124		    dr->ms_state = mes[i].sd_state;
1125		}
1126	    }
1127	}
1128	break;
1129    }
1130    default:
1131	device_printf(sc->mlx_dev, "%s: unknown command 0x%x", __FUNCTION__, mc->mc_mailbox[0]);
1132	break;
1133    }
1134
1135 out:
1136    free(mc->mc_data, M_DEVBUF);
1137    mlx_releasecmd(mc);
1138}
1139
1140/********************************************************************************
1141 * Instigate a poll for one event log message on (sc).
1142 * We only poll for one message at a time, to keep our command usage down.
1143 */
1144static void
1145mlx_periodic_eventlog_poll(struct mlx_softc *sc)
1146{
1147    struct mlx_command	*mc;
1148    void		*result = NULL;
1149    int			error;
1150
1151    debug_called(1);
1152
1153    /* get ourselves a command buffer */
1154    error = 1;
1155    if ((mc = mlx_alloccmd(sc)) == NULL)
1156	goto out;
1157    /* allocate the response structure */
1158    if ((result = malloc(/*sizeof(struct mlx_eventlog_entry)*/1024, M_DEVBUF, M_NOWAIT)) == NULL)
1159	goto out;
1160    /* get a command slot */
1161    if (mlx_getslot(mc))
1162	goto out;
1163
1164    /* map the command so the controller can see it */
1165    mc->mc_data = result;
1166    mc->mc_length = /*sizeof(struct mlx_eventlog_entry)*/1024;
1167    mlx_mapcmd(mc);
1168
1169    /* build the command to get one entry */
1170    mlx_make_type3(mc, MLX_CMD_LOGOP, MLX_LOGOP_GET, 1, sc->mlx_lastevent, 0, 0, mc->mc_dataphys, 0);
1171    mc->mc_complete = mlx_periodic_eventlog_respond;
1172    mc->mc_private = mc;
1173
1174    /* start the command */
1175    if ((error = mlx_start(mc)) != 0)
1176	goto out;
1177
1178    error = 0;			/* success */
1179 out:
1180    if (error != 0) {
1181	if (mc != NULL)
1182	    mlx_releasecmd(mc);
1183	if (result != NULL)
1184	    free(result, M_DEVBUF);
1185    }
1186}
1187
1188/********************************************************************************
1189 * Handle the result of polling for a log message, generate diagnostic output.
1190 * If this wasn't the last message waiting for us, we'll go collect another.
1191 */
1192static char *mlx_sense_messages[] = {
1193    "because write recovery failed",
1194    "because of SCSI bus reset failure",
1195    "because of double check condition",
1196    "because it was removed",
1197    "because of gross error on SCSI chip",
1198    "because of bad tag returned from drive",
1199    "because of timeout on SCSI command",
1200    "because of reset SCSI command issued from system",
1201    "because busy or parity error count exceeded limit",
1202    "because of 'kill drive' command from system",
1203    "because of selection timeout",
1204    "due to SCSI phase sequence error",
1205    "due to unknown status"
1206};
1207
1208static void
1209mlx_periodic_eventlog_respond(struct mlx_command *mc)
1210{
1211    struct mlx_softc		*sc = mc->mc_sc;
1212    struct mlx_eventlog_entry	*el = (struct mlx_eventlog_entry *)mc->mc_data;
1213    char			*reason;
1214
1215    debug_called(1);
1216
1217    sc->mlx_lastevent++;		/* next message... */
1218    if (mc->mc_status == 0) {
1219
1220	/* handle event log message */
1221	switch(el->el_type) {
1222	    /*
1223	     * This is the only sort of message we understand at the moment.
1224	     * The tests here are probably incomplete.
1225	     */
1226	case MLX_LOGMSG_SENSE:	/* sense data */
1227	    /* Mylex vendor-specific message indicating a drive was killed? */
1228	    if ((el->el_sensekey == 9) &&
1229		(el->el_asc == 0x80)) {
1230		if (el->el_asq < (sizeof(mlx_sense_messages) / sizeof(mlx_sense_messages[0]))) {
1231		    reason = mlx_sense_messages[el->el_asq];
1232		} else {
1233		    reason = "for unknown reason";
1234		}
1235		device_printf(sc->mlx_dev, "physical drive %d:%d killed %s\n",
1236			      el->el_channel, el->el_target, reason);
1237	    }
1238	    /* SCSI drive was reset? */
1239	    if ((el->el_sensekey == 6) && (el->el_asc == 0x29)) {
1240		device_printf(sc->mlx_dev, "physical drive %d:%d reset\n",
1241			      el->el_channel, el->el_target);
1242	    }
1243	    /* SCSI drive error? */
1244	    if (!((el->el_sensekey == 0) ||
1245		  ((el->el_sensekey == 2) &&
1246		   (el->el_asc == 0x04) &&
1247		   ((el->el_asq == 0x01) ||
1248		    (el->el_asq == 0x02))))) {
1249		device_printf(sc->mlx_dev, "physical drive %d:%d error log: sense = %d asc = %x asq = %x\n",
1250			      el->el_channel, el->el_target, el->el_sensekey, el->el_asc, el->el_asq);
1251		device_printf(sc->mlx_dev, "  info %4D csi %4D\n", el->el_information, ":", el->el_csi, ":");
1252	    }
1253	    break;
1254
1255	default:
1256	    device_printf(sc->mlx_dev, "unknown log message type 0x%x\n", el->el_type);
1257	    break;
1258	}
1259    } else {
1260	device_printf(sc->mlx_dev, "error reading message log - %s\n", mlx_diagnose_command(mc));
1261    }
1262
1263    /* dispose of command and data */
1264    free(mc->mc_data, M_DEVBUF);
1265    mlx_releasecmd(mc);
1266
1267    /* is there another message to obtain? */
1268    if (sc->mlx_lastevent != sc->mlx_currevent)
1269	mlx_periodic_eventlog_poll(sc);
1270}
1271
1272/********************************************************************************
1273 * Handle the completion of a rebuild operation.
1274 */
1275static void
1276mlx_periodic_rebuild(struct mlx_command *mc)
1277{
1278    struct mlx_softc		*sc = mc->mc_sc;
1279    struct mlx_rebuild_stat	*mr = (struct mlx_rebuild_stat *)mc->mc_private;
1280
1281    switch(mc->mc_status) {
1282    case 0:				/* all OK, rebuild still running */
1283	sc->mlx_rebuildstat = mr->rb_remaining;
1284	break;
1285
1286    case 0x0105:			/* rebuild/check finished */
1287	if (sc->mlx_rebuild >= 0) {
1288	    device_printf(sc->mlx_sysdrive[sc->mlx_rebuild].ms_disk, "rebuild completed\n");
1289	    sc->mlx_rebuild = -1;
1290	} else if (sc->mlx_check >= 0) {
1291	    device_printf(sc->mlx_sysdrive[sc->mlx_check].ms_disk, "consistency check completed\n");
1292	    sc->mlx_check = -1;
1293	} else {
1294	    device_printf(sc->mlx_dev, "consistency check completed\n");
1295	}
1296	break;
1297    }
1298    free(mc->mc_data, M_DEVBUF);
1299    mlx_releasecmd(mc);
1300}
1301
1302/********************************************************************************
1303 ********************************************************************************
1304                                                                    Channel Pause
1305 ********************************************************************************
1306 ********************************************************************************/
1307
1308/********************************************************************************
1309 * It's time to perform a channel pause action for (sc), either start or stop
1310 * the pause.
1311 */
1312static void
1313mlx_pause_action(struct mlx_softc *sc)
1314{
1315    struct mlx_command	*mc;
1316    int			failsafe, i, command;
1317
1318    /* What are we doing here? */
1319    if (sc->mlx_pause.mp_when == 0) {
1320	command = MLX_CMD_STARTCHANNEL;
1321	failsafe = 0;
1322
1323    } else {
1324	command = MLX_CMD_STOPCHANNEL;
1325
1326	/*
1327	 * Channels will always start again after the failsafe period,
1328	 * which is specified in multiples of 30 seconds.
1329	 * This constrains us to a maximum pause of 450 seconds.
1330	 */
1331	failsafe = ((sc->mlx_pause.mp_howlong - time_second) + 5) / 30;
1332	if (failsafe > 0xf) {
1333	    failsafe = 0xf;
1334	    sc->mlx_pause.mp_howlong = time_second + (0xf * 30) - 5;
1335	}
1336    }
1337
1338    /* build commands for every channel requested */
1339    for (i = 0; i < sc->mlx_enq2->me_actual_channels; i++) {
1340	if ((1 << i) & sc->mlx_pause.mp_which) {
1341
1342	    /* get ourselves a command buffer */
1343	    if ((mc = mlx_alloccmd(sc)) == NULL)
1344		goto fail;
1345	    /* get a command slot */
1346	    mc->mc_flags |= MLX_CMD_PRIORITY;
1347	    if (mlx_getslot(mc))
1348		goto fail;
1349
1350	    /* build the command */
1351	    mlx_make_type2(mc, command, (failsafe << 4) | i, 0, 0, 0, 0, 0, 0, 0);
1352	    mc->mc_complete = mlx_pause_done;
1353	    mc->mc_private = sc;		/* XXX not needed */
1354	    if (mlx_start(mc))
1355		goto fail;
1356	    /* command submitted OK */
1357	    return;
1358
1359	fail:
1360	    device_printf(sc->mlx_dev, "%s failed for channel %d\n",
1361			  command == MLX_CMD_STOPCHANNEL ? "pause" : "resume", i);
1362	    if (mc != NULL)
1363		mlx_releasecmd(mc);
1364	}
1365    }
1366}
1367
1368static void
1369mlx_pause_done(struct mlx_command *mc)
1370{
1371    struct mlx_softc	*sc = mc->mc_sc;
1372    int			command = mc->mc_mailbox[0];
1373    int			channel = mc->mc_mailbox[2] & 0xf;
1374
1375    if (mc->mc_status != 0) {
1376	device_printf(sc->mlx_dev, "%s command failed - %s\n",
1377		      command == MLX_CMD_STOPCHANNEL ? "pause" : "resume", mlx_diagnose_command(mc));
1378    } else if (command == MLX_CMD_STOPCHANNEL) {
1379	device_printf(sc->mlx_dev, "channel %d pausing for %ld seconds\n",
1380		      channel, (long)(sc->mlx_pause.mp_howlong - time_second));
1381    } else {
1382	device_printf(sc->mlx_dev, "channel %d resuming\n", channel);
1383    }
1384    mlx_releasecmd(mc);
1385}
1386
1387/********************************************************************************
1388 ********************************************************************************
1389                                                               Command Submission
1390 ********************************************************************************
1391 ********************************************************************************/
1392
1393/********************************************************************************
1394 * Perform an Enquiry command using a type-3 command buffer and a return a single
1395 * linear result buffer.  If the completion function is specified, it will
1396 * be called with the completed command (and the result response will not be
1397 * valid until that point).  Otherwise, the command will either be busy-waited
1398 * for (interrupts not enabled), or slept for.
1399 */
1400static void *
1401mlx_enquire(struct mlx_softc *sc, int command, size_t bufsize, void (* complete)(struct mlx_command *mc))
1402{
1403    struct mlx_command	*mc;
1404    void		*result;
1405    int			error;
1406
1407    debug_called(1);
1408
1409    /* get ourselves a command buffer */
1410    error = 1;
1411    result = NULL;
1412    if ((mc = mlx_alloccmd(sc)) == NULL)
1413	goto out;
1414    /* allocate the response structure */
1415    if ((result = malloc(bufsize, M_DEVBUF, M_NOWAIT)) == NULL)
1416	goto out;
1417    /* get a command slot */
1418    mc->mc_flags |= MLX_CMD_PRIORITY | MLX_CMD_DATAOUT;
1419    if (mlx_getslot(mc))
1420	goto out;
1421
1422    /* map the command so the controller can see it */
1423    mc->mc_data = result;
1424    mc->mc_length = bufsize;
1425    mlx_mapcmd(mc);
1426
1427    /* build an enquiry command */
1428    mlx_make_type2(mc, command, 0, 0, 0, 0, 0, 0, mc->mc_dataphys, 0);
1429
1430    /* do we want a completion callback? */
1431    if (complete != NULL) {
1432	mc->mc_complete = complete;
1433	mc->mc_private = mc;
1434	if ((error = mlx_start(mc)) != 0)
1435	    goto out;
1436    } else {
1437	/* run the command in either polled or wait mode */
1438	if ((sc->mlx_state & MLX_STATE_INTEN) ? mlx_wait_command(mc) : mlx_poll_command(mc))
1439	    goto out;
1440
1441	/* command completed OK? */
1442	if (mc->mc_status != 0) {
1443	    device_printf(sc->mlx_dev, "ENQUIRY failed - %s\n", mlx_diagnose_command(mc));
1444	    goto out;
1445	}
1446    }
1447    error = 0;			/* success */
1448 out:
1449    /* we got a command, but nobody else will free it */
1450    if ((complete == NULL) && (mc != NULL))
1451	mlx_releasecmd(mc);
1452    /* we got an error, and we allocated a result */
1453    if ((error != 0) && (result != NULL)) {
1454	free(result, M_DEVBUF);
1455	result = NULL;
1456    }
1457    return(result);
1458}
1459
1460
1461/********************************************************************************
1462 * Perform a Flush command on the nominated controller.
1463 *
1464 * May be called with interrupts enabled or disabled; will not return until
1465 * the flush operation completes or fails.
1466 */
1467static int
1468mlx_flush(struct mlx_softc *sc)
1469{
1470    struct mlx_command	*mc;
1471    int			error;
1472
1473    debug_called(1);
1474
1475    /* get ourselves a command buffer */
1476    error = 1;
1477    if ((mc = mlx_alloccmd(sc)) == NULL)
1478	goto out;
1479    /* get a command slot */
1480    if (mlx_getslot(mc))
1481	goto out;
1482
1483    /* build a flush command */
1484    mlx_make_type2(mc, MLX_CMD_FLUSH, 0, 0, 0, 0, 0, 0, 0, 0);
1485
1486    /* can't assume that interrupts are going to work here, so play it safe */
1487    if (mlx_poll_command(mc))
1488	goto out;
1489
1490    /* command completed OK? */
1491    if (mc->mc_status != 0) {
1492	device_printf(sc->mlx_dev, "FLUSH failed - %s\n", mlx_diagnose_command(mc));
1493	goto out;
1494    }
1495
1496    error = 0;			/* success */
1497 out:
1498    if (mc != NULL)
1499	mlx_releasecmd(mc);
1500    return(error);
1501}
1502
1503/********************************************************************************
1504 * Start a background rebuild on the nominated controller/channel/target.
1505 *
1506 * May be called with interrupts enabled or disabled; will return as soon as the
1507 * operation has started or been refused.
1508 */
1509static int
1510mlx_rebuild(struct mlx_softc *sc, int channel, int target)
1511{
1512    struct mlx_command	*mc;
1513    int			error;
1514
1515    debug_called(1);
1516
1517    /* get ourselves a command buffer */
1518    error = 0x10000;
1519    if ((mc = mlx_alloccmd(sc)) == NULL)
1520	goto out;
1521    /* get a command slot */
1522    if (mlx_getslot(mc))
1523	goto out;
1524
1525    /* build a rebuild command */
1526    mlx_make_type2(mc, MLX_CMD_REBUILDASYNC, channel, target, 0, 0, 0, 0, 0, 0);
1527
1528    /* run the command in either polled or wait mode */
1529    if ((sc->mlx_state & MLX_STATE_INTEN) ? mlx_wait_command(mc) : mlx_poll_command(mc))
1530	goto out;
1531
1532    /* command completed OK? */
1533    if (mc->mc_status != 0) {
1534	device_printf(sc->mlx_dev, "REBUILD ASYNC failed - %s\n", mlx_diagnose_command(mc));
1535    } else {
1536	device_printf(sc->mlx_sysdrive[sc->mlx_rebuild].ms_disk, "rebuild started");
1537    }
1538    error = mc->mc_status;
1539
1540 out:
1541    if (mc != NULL)
1542	mlx_releasecmd(mc);
1543    return(error);
1544}
1545
1546/********************************************************************************
1547 * Run the command (mc) and return when it completes.
1548 *
1549 * Interrupts need to be enabled; returns nonzero on error.
1550 */
1551static int
1552mlx_wait_command(struct mlx_command *mc)
1553{
1554    struct mlx_softc	*sc = mc->mc_sc;
1555    int			error, count;
1556
1557    debug_called(1);
1558
1559    mc->mc_complete = NULL;
1560    mc->mc_private = mc;		/* wake us when you're done */
1561    if ((error = mlx_start(mc)) != 0)
1562	return(error);
1563
1564    count = 0;
1565    /* XXX better timeout? */
1566    while ((mc->mc_status == MLX_STATUS_BUSY) && (count < 30)) {
1567	tsleep(mc->mc_private, PRIBIO | PCATCH, "mlxwcmd", hz);
1568    }
1569
1570    if (mc->mc_status != 0) {
1571	device_printf(sc->mlx_dev, "command failed - %s\n", mlx_diagnose_command(mc));
1572	return(EIO);
1573    }
1574    return(0);
1575}
1576
1577
1578/********************************************************************************
1579 * Start the command (mc) and busy-wait for it to complete.
1580 *
1581 * Should only be used when interrupts can't be relied upon. Returns 0 on
1582 * success, nonzero on error.
1583 * Successfully completed commands are dequeued.
1584 */
1585static int
1586mlx_poll_command(struct mlx_command *mc)
1587{
1588    struct mlx_softc	*sc = mc->mc_sc;
1589    int			error, count, s;
1590
1591    debug_called(1);
1592
1593    mc->mc_complete = NULL;
1594    mc->mc_private = NULL;	/* we will poll for it */
1595    if ((error = mlx_start(mc)) != 0)
1596	return(error);
1597
1598    count = 0;
1599    do {
1600	/* poll for completion */
1601	mlx_done(mc->mc_sc);
1602
1603    } while ((mc->mc_status == MLX_STATUS_BUSY) && (count++ < 15000000));
1604    if (mc->mc_status != MLX_STATUS_BUSY) {
1605	s = splbio();
1606	TAILQ_REMOVE(&sc->mlx_work, mc, mc_link);
1607	splx(s);
1608	return(0);
1609    }
1610    device_printf(sc->mlx_dev, "I/O error 0x%x\n", mc->mc_status);
1611    return(EIO);
1612}
1613
1614/********************************************************************************
1615 * Pull as much work off the softc's work queue as possible and give it to the
1616 * controller.  Leave a couple of slots free for emergencies.
1617 *
1618 * Must be called at splbio or in an equivalent fashion that prevents
1619 * reentry or activity on the bufq.
1620 */
1621static void
1622mlx_startio(struct mlx_softc *sc)
1623{
1624    struct mlx_command	*mc;
1625    struct mlxd_softc	*mlxd;
1626    struct buf		*bp;
1627    int			blkcount;
1628    int			driveno;
1629    int			cmd;
1630    int			s;
1631
1632    /* avoid reentrancy */
1633    if (mlx_lock_tas(sc, MLX_LOCK_STARTING))
1634	return;
1635
1636    /* spin until something prevents us from doing any work */
1637    s = splbio();
1638    for (;;) {
1639
1640	/* see if there's work to be done */
1641	if ((bp = bufq_first(&sc->mlx_bufq)) == NULL)
1642	    break;
1643	/* get a command */
1644	if ((mc = mlx_alloccmd(sc)) == NULL)
1645	    break;
1646	/* get a slot for the command */
1647	if (mlx_getslot(mc) != 0) {
1648	    mlx_releasecmd(mc);
1649	    break;
1650	}
1651	/* get the buf containing our work */
1652	bufq_remove(&sc->mlx_bufq, bp);
1653	sc->mlx_waitbufs--;
1654	splx(s);
1655
1656	/* connect the buf to the command */
1657	mc->mc_complete = mlx_completeio;
1658	mc->mc_private = bp;
1659	mc->mc_data = bp->b_data;
1660	mc->mc_length = bp->b_bcount;
1661	if (bp->b_iocmd == BIO_READ) {
1662	    mc->mc_flags |= MLX_CMD_DATAIN;
1663	    cmd = MLX_CMD_READSG;
1664	} else {
1665	    mc->mc_flags |= MLX_CMD_DATAOUT;
1666	    cmd = MLX_CMD_WRITESG;
1667	}
1668
1669	/* map the command so the controller can work with it */
1670	mlx_mapcmd(mc);
1671
1672	/* build a suitable I/O command (assumes 512-byte rounded transfers) */
1673	mlxd = (struct mlxd_softc *)bp->b_dev->si_drv1;
1674	driveno = mlxd->mlxd_drive - sc->mlx_sysdrive;
1675	blkcount = (bp->b_bcount + MLX_BLKSIZE - 1) / MLX_BLKSIZE;
1676
1677	if ((bp->b_pblkno + blkcount) > sc->mlx_sysdrive[driveno].ms_size)
1678	    device_printf(sc->mlx_dev, "I/O beyond end of unit (%u,%d > %u)\n",
1679			  bp->b_pblkno, blkcount, sc->mlx_sysdrive[driveno].ms_size);
1680
1681	/*
1682	 * Build the I/O command.  Note that the SG list type bits are set to zero,
1683	 * denoting the format of SG list that we are using.
1684	 */
1685	if (sc->mlx_iftype == MLX_IFTYPE_2) {
1686	    mlx_make_type1(mc, (cmd == MLX_CMD_WRITESG) ? MLX_CMD_WRITESG_OLD : MLX_CMD_READSG_OLD,
1687			   blkcount & 0xff, 				/* xfer length low byte */
1688			   bp->b_pblkno,				/* physical block number */
1689			   driveno,					/* target drive number */
1690			   mc->mc_sgphys,				/* location of SG list */
1691			   mc->mc_nsgent & 0x3f);			/* size of SG list (top 3 bits clear) */
1692	} else {
1693	    mlx_make_type5(mc, cmd,
1694			   blkcount & 0xff, 				/* xfer length low byte */
1695			   (driveno << 3) | ((blkcount >> 8) & 0x07),	/* target and length high 3 bits */
1696			   bp->b_pblkno,				/* physical block number */
1697			   mc->mc_sgphys,				/* location of SG list */
1698			   mc->mc_nsgent & 0x3f);			/* size of SG list (top 3 bits clear) */
1699	}
1700
1701	/* try to give command to controller */
1702	if (mlx_start(mc) != 0) {
1703	    /* fail the command */
1704	    mc->mc_status = MLX_STATUS_WEDGED;
1705	    mlx_completeio(mc);
1706	}
1707	s = splbio();
1708    }
1709    splx(s);
1710    mlx_lock_clr(sc, MLX_LOCK_STARTING);
1711}
1712
1713/********************************************************************************
1714 * Handle completion of an I/O command.
1715 */
1716static void
1717mlx_completeio(struct mlx_command *mc)
1718{
1719    struct mlx_softc	*sc = mc->mc_sc;
1720    struct buf		*bp = (struct buf *)mc->mc_private;
1721    struct mlxd_softc	*mlxd = (struct mlxd_softc *)bp->b_dev->si_drv1;
1722
1723    if (mc->mc_status != MLX_STATUS_OK) {	/* could be more verbose here? */
1724	bp->b_error = EIO;
1725	bp->b_flags |= B_ERROR;
1726
1727	switch(mc->mc_status) {
1728	case MLX_STATUS_RDWROFFLINE:		/* system drive has gone offline */
1729	    device_printf(mlxd->mlxd_dev, "drive offline\n");
1730	    /* should signal this with a return code */
1731	    mlxd->mlxd_drive->ms_state = MLX_SYSD_OFFLINE;
1732	    break;
1733
1734	default:				/* other I/O error */
1735	    device_printf(sc->mlx_dev, "I/O error - %s\n", mlx_diagnose_command(mc));
1736#if 0
1737	    device_printf(sc->mlx_dev, "  b_bcount %ld  blkcount %ld  b_pblkno %d\n",
1738			  bp->b_bcount, bp->b_bcount / MLX_BLKSIZE, bp->b_pblkno);
1739	    device_printf(sc->mlx_dev, "  %13D\n", mc->mc_mailbox, " ");
1740#endif
1741	    break;
1742	}
1743    }
1744    mlx_releasecmd(mc);
1745    mlxd_intr(bp);
1746}
1747
1748/********************************************************************************
1749 * Take a command from user-space and try to run it.
1750 *
1751 * XXX Note that this can't perform very much in the way of error checking, and
1752 *     as such, applications _must_ be considered trustworthy.
1753 * XXX Commands using S/G for data are not supported.
1754 */
1755static int
1756mlx_user_command(struct mlx_softc *sc, struct mlx_usercommand *mu)
1757{
1758    struct mlx_command	*mc;
1759    struct mlx_dcdb	*dcdb;
1760    void		*kbuf;
1761    int			error;
1762
1763    debug_called(0);
1764
1765    kbuf = NULL;
1766    mc = NULL;
1767    dcdb = NULL;
1768    error = ENOMEM;
1769
1770    /* get ourselves a command and copy in from user space */
1771    if ((mc = mlx_alloccmd(sc)) == NULL)
1772	goto out;
1773    bcopy(mu->mu_command, mc->mc_mailbox, sizeof(mc->mc_mailbox));
1774    debug(0, "got command buffer");
1775
1776    /* if we need a buffer for data transfer, allocate one and copy in its initial contents */
1777    if (mu->mu_datasize > 0) {
1778	if (((kbuf = malloc(mu->mu_datasize, M_DEVBUF, M_WAITOK)) == NULL) ||
1779	    (error = copyin(mu->mu_buf, kbuf, mu->mu_datasize)))
1780	    goto out;
1781	debug(0, "got kernel buffer");
1782    }
1783
1784    /* get a command slot */
1785    if (mlx_getslot(mc))
1786	goto out;
1787    debug(0, "got a slot");
1788
1789    /* map the command so the controller can see it */
1790    mc->mc_data = kbuf;
1791    mc->mc_length = mu->mu_datasize;
1792    mlx_mapcmd(mc);
1793    debug(0, "mapped");
1794
1795    /*
1796     * If this is a passthrough SCSI command, the DCDB is packed at the
1797     * beginning of the data area.  Fix up the DCDB to point to the correct physical
1798     * address and override any bufptr supplied by the caller since we know
1799     * what it's meant to be.
1800     */
1801    if (mc->mc_mailbox[0] == MLX_CMD_DIRECT_CDB) {
1802	dcdb = (struct mlx_dcdb *)kbuf;
1803	dcdb->dcdb_physaddr = mc->mc_dataphys + sizeof(*dcdb);
1804	mu->mu_bufptr = 8;
1805    }
1806
1807    /*
1808     * If there's a data buffer, fix up the command's buffer pointer.
1809     */
1810    if (mu->mu_datasize > 0) {
1811
1812	/* range check the pointer to physical buffer address */
1813	if ((mu->mu_bufptr < 0) || (mu->mu_bufptr > (sizeof(mu->mu_command) - sizeof(u_int32_t)))) {
1814	    error = EINVAL;
1815	    goto out;
1816	}
1817	mc->mc_mailbox[mu->mu_bufptr    ] =  mc->mc_dataphys        & 0xff;
1818	mc->mc_mailbox[mu->mu_bufptr + 1] = (mc->mc_dataphys >> 8)  & 0xff;
1819	mc->mc_mailbox[mu->mu_bufptr + 2] = (mc->mc_dataphys >> 16) & 0xff;
1820	mc->mc_mailbox[mu->mu_bufptr + 3] = (mc->mc_dataphys >> 24) & 0xff;
1821    }
1822    debug(0, "command fixup");
1823
1824    /* submit the command and wait */
1825    if ((error = mlx_wait_command(mc)) != 0)
1826	goto out;
1827
1828    /* copy out status and data */
1829    mu->mu_status = mc->mc_status;
1830    if ((mu->mu_datasize > 0) && ((error = copyout(kbuf, mu->mu_buf, mu->mu_datasize))))
1831	goto out;
1832    error = 0;
1833
1834 out:
1835    mlx_releasecmd(mc);
1836    if (kbuf != NULL)
1837	free(kbuf, M_DEVBUF);
1838    return(error);
1839}
1840
1841/********************************************************************************
1842 ********************************************************************************
1843                                                        Command I/O to Controller
1844 ********************************************************************************
1845 ********************************************************************************/
1846
1847/********************************************************************************
1848 * Find a free command slot for (mc).
1849 *
1850 * Don't hand out a slot to a normal-priority command unless there are at least
1851 * 4 slots free for priority commands.
1852 */
1853static int
1854mlx_getslot(struct mlx_command *mc)
1855{
1856    struct mlx_softc	*sc = mc->mc_sc;
1857    int			s, slot;
1858
1859    debug_called(1);
1860
1861    /* enforce slot-usage limit */
1862    if (sc->mlx_busycmds >= ((mc->mc_flags & MLX_CMD_PRIORITY) ?
1863			     sc->mlx_maxiop : sc->mlx_maxiop - 4))
1864	return(EBUSY);
1865
1866    /*
1867     * Allocate an outstanding command slot
1868     *
1869     * XXX linear search is slow
1870     */
1871    s = splbio();
1872    for (slot = 0; slot < sc->mlx_maxiop; slot++) {
1873	debug(2, "try slot %d", slot);
1874	if (sc->mlx_busycmd[slot] == NULL)
1875	    break;
1876    }
1877    if (slot < sc->mlx_maxiop) {
1878	sc->mlx_busycmd[slot] = mc;
1879	sc->mlx_busycmds++;
1880    }
1881    splx(s);
1882
1883    /* out of slots? */
1884    if (slot >= sc->mlx_maxiop)
1885	return(EBUSY);
1886
1887    debug(2, "got slot %d", slot);
1888    mc->mc_slot = slot;
1889    return(0);
1890}
1891
1892/********************************************************************************
1893 * Map/unmap (mc)'s data in the controller's addressable space.
1894 */
1895static void
1896mlx_setup_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error)
1897{
1898    struct mlx_command	*mc = (struct mlx_command *)arg;
1899    struct mlx_softc	*sc = mc->mc_sc;
1900    struct mlx_sgentry	*sg;
1901    int			i;
1902
1903    debug_called(1);
1904
1905    /* get base address of s/g table */
1906    sg = sc->mlx_sgtable + (mc->mc_slot * sc->mlx_sg_nseg);
1907
1908    /* save s/g table information in command */
1909    mc->mc_nsgent = nsegments;
1910    mc->mc_sgphys = sc->mlx_sgbusaddr + (mc->mc_slot * sc->mlx_sg_nseg * sizeof(struct mlx_sgentry));
1911    mc->mc_dataphys = segs[0].ds_addr;
1912
1913    /* populate s/g table */
1914    for (i = 0; i < nsegments; i++, sg++) {
1915	sg->sg_addr = segs[i].ds_addr;
1916	sg->sg_count = segs[i].ds_len;
1917    }
1918}
1919
1920static void
1921mlx_mapcmd(struct mlx_command *mc)
1922{
1923    struct mlx_softc	*sc = mc->mc_sc;
1924
1925    debug_called(1);
1926
1927    /* if the command involves data at all */
1928    if (mc->mc_data != NULL) {
1929
1930	/* map the data buffer into bus space and build the s/g list */
1931	bus_dmamap_load(sc->mlx_buffer_dmat, mc->mc_dmamap, mc->mc_data, mc->mc_length,
1932			mlx_setup_dmamap, mc, 0);
1933	if (mc->mc_flags & MLX_CMD_DATAIN)
1934	    bus_dmamap_sync(sc->mlx_buffer_dmat, mc->mc_dmamap, BUS_DMASYNC_PREREAD);
1935	if (mc->mc_flags & MLX_CMD_DATAOUT)
1936	    bus_dmamap_sync(sc->mlx_buffer_dmat, mc->mc_dmamap, BUS_DMASYNC_PREWRITE);
1937    }
1938}
1939
1940static void
1941mlx_unmapcmd(struct mlx_command *mc)
1942{
1943    struct mlx_softc	*sc = mc->mc_sc;
1944
1945    debug_called(1);
1946
1947    /* if the command involved data at all */
1948    if (mc->mc_data != NULL) {
1949
1950	if (mc->mc_flags & MLX_CMD_DATAIN)
1951	    bus_dmamap_sync(sc->mlx_buffer_dmat, mc->mc_dmamap, BUS_DMASYNC_POSTREAD);
1952	if (mc->mc_flags & MLX_CMD_DATAOUT)
1953	    bus_dmamap_sync(sc->mlx_buffer_dmat, mc->mc_dmamap, BUS_DMASYNC_POSTWRITE);
1954
1955	bus_dmamap_unload(sc->mlx_buffer_dmat, mc->mc_dmamap);
1956    }
1957}
1958
1959/********************************************************************************
1960 * Try to deliver (mc) to the controller.
1961 *
1962 * Can be called at any interrupt level, with or without interrupts enabled.
1963 */
1964static int
1965mlx_start(struct mlx_command *mc)
1966{
1967    struct mlx_softc	*sc = mc->mc_sc;
1968    int			i, s, done;
1969
1970    debug_called(1);
1971
1972    /* save the slot number as ident so we can handle this command when complete */
1973    mc->mc_mailbox[0x1] = mc->mc_slot;
1974
1975    /* mark the command as currently being processed */
1976    mc->mc_status = MLX_STATUS_BUSY;
1977
1978    /* set a default 60-second timeout  XXX tunable?  XXX not currently used */
1979    mc->mc_timeout = time_second + 60;
1980
1981    /* spin waiting for the mailbox */
1982    for (i = 100000, done = 0; (i > 0) && !done; i--) {
1983	s = splbio();
1984	if (sc->mlx_tryqueue(sc, mc)) {
1985	    done = 1;
1986	    /* move command to work queue */
1987	    TAILQ_INSERT_TAIL(&sc->mlx_work, mc, mc_link);
1988	}
1989	splx(s);	/* drop spl to allow completion interrupts */
1990    }
1991
1992    /* command is enqueued */
1993    if (done)
1994	return(0);
1995
1996    /*
1997     * We couldn't get the controller to take the command.  Revoke the slot
1998     * that the command was given and return it with a bad status.
1999     */
2000    sc->mlx_busycmd[mc->mc_slot] = NULL;
2001    device_printf(sc->mlx_dev, "controller wedged (not taking commands)\n");
2002    mc->mc_status = MLX_STATUS_WEDGED;
2003    mlx_complete(sc);
2004    return(EIO);
2005}
2006
2007/********************************************************************************
2008 * Poll the controller (sc) for completed commands.
2009 * Update command status and free slots for reuse.  If any slots were freed,
2010 * new commands may be posted.
2011 *
2012 * Returns nonzero if one or more commands were completed.
2013 */
2014static int
2015mlx_done(struct mlx_softc *sc)
2016{
2017    struct mlx_command	*mc;
2018    int			s, result;
2019    u_int8_t		slot;
2020    u_int16_t		status;
2021
2022    debug_called(2);
2023
2024    result = 0;
2025
2026    /* loop collecting completed commands */
2027    s = splbio();
2028    for (;;) {
2029	/* poll for a completed command's identifier and status */
2030	if (sc->mlx_findcomplete(sc, &slot, &status)) {
2031	    result = 1;
2032	    mc = sc->mlx_busycmd[slot];			/* find command */
2033	    if (mc != NULL) {				/* paranoia */
2034		if (mc->mc_status == MLX_STATUS_BUSY) {
2035		    mc->mc_status = status;		/* save status */
2036
2037		    /* free slot for reuse */
2038		    sc->mlx_busycmd[slot] = NULL;
2039		    sc->mlx_busycmds--;
2040		} else {
2041		    device_printf(sc->mlx_dev, "duplicate done event for slot %d\n", slot);
2042		}
2043	    } else {
2044		device_printf(sc->mlx_dev, "done event for nonbusy slot %d\n", slot);
2045	    }
2046	} else {
2047	    break;
2048	}
2049    }
2050
2051    /* if we've completed any commands, try posting some more */
2052    if (result)
2053	mlx_startio(sc);
2054
2055    /* handle completion and timeouts */
2056    mlx_complete(sc);
2057
2058    return(result);
2059}
2060
2061/********************************************************************************
2062 * Perform post-completion processing for commands on (sc).
2063 */
2064static void
2065mlx_complete(struct mlx_softc *sc)
2066{
2067    struct mlx_command	*mc, *nc;
2068    int			s, count;
2069
2070    debug_called(2);
2071
2072    /* avoid reentrancy  XXX might want to signal and request a restart */
2073    if (mlx_lock_tas(sc, MLX_LOCK_COMPLETING))
2074	return;
2075
2076    s = splbio();
2077    count = 0;
2078
2079    /* scan the list of busy/done commands */
2080    mc = TAILQ_FIRST(&sc->mlx_work);
2081    while (mc != NULL) {
2082	nc = TAILQ_NEXT(mc, mc_link);
2083
2084	/* Command has been completed in some fashion */
2085	if (mc->mc_status != MLX_STATUS_BUSY) {
2086
2087	    /* unmap the command's data buffer */
2088	    mlx_unmapcmd(mc);
2089	    /*
2090	     * Does the command have a completion handler?
2091	     */
2092	    if (mc->mc_complete != NULL) {
2093		/* remove from list and give to handler */
2094		TAILQ_REMOVE(&sc->mlx_work, mc, mc_link);
2095		mc->mc_complete(mc);
2096
2097		/*
2098		 * Is there a sleeper waiting on this command?
2099		 */
2100	    } else if (mc->mc_private != NULL) {	/* sleeping caller wants to know about it */
2101
2102		/* remove from list and wake up sleeper */
2103		TAILQ_REMOVE(&sc->mlx_work, mc, mc_link);
2104		wakeup_one(mc->mc_private);
2105
2106		/*
2107		 * Leave the command for a caller that's polling for it.
2108		 */
2109	    } else {
2110	    }
2111	}
2112	mc = nc;
2113    }
2114    splx(s);
2115
2116    mlx_lock_clr(sc, MLX_LOCK_COMPLETING);
2117}
2118
2119/********************************************************************************
2120 ********************************************************************************
2121                                                        Command Buffer Management
2122 ********************************************************************************
2123 ********************************************************************************/
2124
2125/********************************************************************************
2126 * Get a new command buffer.
2127 *
2128 * This may return NULL in low-memory cases.
2129 *
2130 * Note that using malloc() is expensive (the command buffer is << 1 page) but
2131 * necessary if we are to be a loadable module before the zone allocator is fixed.
2132 *
2133 * If possible, we recycle a command buffer that's been used before.
2134 *
2135 * XXX Note that command buffers are not cleaned out - it is the caller's
2136 *     responsibility to ensure that all required fields are filled in before
2137 *     using a buffer.
2138 */
2139static struct mlx_command *
2140mlx_alloccmd(struct mlx_softc *sc)
2141{
2142    struct mlx_command	*mc;
2143    int			error;
2144    int			s;
2145
2146    debug_called(1);
2147
2148    s = splbio();
2149    if ((mc = TAILQ_FIRST(&sc->mlx_freecmds)) != NULL)
2150	TAILQ_REMOVE(&sc->mlx_freecmds, mc, mc_link);
2151    splx(s);
2152
2153    /* allocate a new command buffer? */
2154    if (mc == NULL) {
2155	mc = (struct mlx_command *)malloc(sizeof(*mc), M_DEVBUF, M_NOWAIT);
2156	if (mc != NULL) {
2157	    bzero(mc, sizeof(*mc));
2158	    mc->mc_sc = sc;
2159	    error = bus_dmamap_create(sc->mlx_buffer_dmat, 0, &mc->mc_dmamap);
2160	    if (error) {
2161		free(mc, M_DEVBUF);
2162		return(NULL);
2163	    }
2164	}
2165    }
2166    return(mc);
2167}
2168
2169/********************************************************************************
2170 * Release a command buffer for recycling.
2171 *
2172 * XXX It might be a good idea to limit the number of commands we save for reuse
2173 *     if it's shown that this list bloats out massively.
2174 */
2175static void
2176mlx_releasecmd(struct mlx_command *mc)
2177{
2178    int		s;
2179
2180    debug_called(1);
2181
2182    s = splbio();
2183    TAILQ_INSERT_HEAD(&mc->mc_sc->mlx_freecmds, mc, mc_link);
2184    splx(s);
2185}
2186
2187/********************************************************************************
2188 * Permanently discard a command buffer.
2189 */
2190static void
2191mlx_freecmd(struct mlx_command *mc)
2192{
2193    struct mlx_softc	*sc = mc->mc_sc;
2194
2195    debug_called(1);
2196    bus_dmamap_destroy(sc->mlx_buffer_dmat, mc->mc_dmamap);
2197    free(mc, M_DEVBUF);
2198}
2199
2200
2201/********************************************************************************
2202 ********************************************************************************
2203                                                Type 3 interface accessor methods
2204 ********************************************************************************
2205 ********************************************************************************/
2206
2207/********************************************************************************
2208 * Try to give (mc) to the controller.  Returns 1 if successful, 0 on failure
2209 * (the controller is not ready to take a command).
2210 *
2211 * Must be called at splbio or in a fashion that prevents reentry.
2212 */
2213static int
2214mlx_v3_tryqueue(struct mlx_softc *sc, struct mlx_command *mc)
2215{
2216    int		i;
2217
2218    debug_called(2);
2219
2220    /* ready for our command? */
2221    if (!(MLX_V3_GET_IDBR(sc) & MLX_V3_IDB_FULL)) {
2222	/* copy mailbox data to window */
2223	for (i = 0; i < 13; i++)
2224	    MLX_V3_PUT_MAILBOX(sc, i, mc->mc_mailbox[i]);
2225
2226	/* post command */
2227	MLX_V3_PUT_IDBR(sc, MLX_V3_IDB_FULL);
2228	return(1);
2229    }
2230    return(0);
2231}
2232
2233/********************************************************************************
2234 * See if a command has been completed, if so acknowledge its completion
2235 * and recover the slot number and status code.
2236 *
2237 * Must be called at splbio or in a fashion that prevents reentry.
2238 */
2239static int
2240mlx_v3_findcomplete(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status)
2241{
2242
2243    debug_called(2);
2244
2245    /* status available? */
2246    if (MLX_V3_GET_ODBR(sc) & MLX_V3_ODB_SAVAIL) {
2247	*slot = MLX_V3_GET_STATUS_IDENT(sc);		/* get command identifier */
2248	*status = MLX_V3_GET_STATUS(sc);		/* get status */
2249
2250	/* acknowledge completion */
2251	MLX_V3_PUT_ODBR(sc, MLX_V3_ODB_SAVAIL);
2252	MLX_V3_PUT_IDBR(sc, MLX_V3_IDB_SACK);
2253	return(1);
2254    }
2255    return(0);
2256}
2257
2258/********************************************************************************
2259 * Enable/disable interrupts as requested. (No acknowledge required)
2260 *
2261 * Must be called at splbio or in a fashion that prevents reentry.
2262 */
2263static void
2264mlx_v3_intaction(struct mlx_softc *sc, int action)
2265{
2266    debug_called(1);
2267
2268    switch(action) {
2269    case MLX_INTACTION_DISABLE:
2270	MLX_V3_PUT_IER(sc, 0);
2271	sc->mlx_state &= ~MLX_STATE_INTEN;
2272	break;
2273    case MLX_INTACTION_ENABLE:
2274	MLX_V3_PUT_IER(sc, 1);
2275	sc->mlx_state |= MLX_STATE_INTEN;
2276	break;
2277    }
2278}
2279
2280/********************************************************************************
2281 * Poll for firmware error codes during controller initialisation.
2282 * Returns 0 if initialisation is complete, 1 if still in progress but no
2283 * error has been fetched, 2 if an error has been retrieved.
2284 */
2285static int
2286mlx_v3_fw_handshake(struct mlx_softc *sc, int *error, int *param1, int *param2)
2287{
2288    u_int8_t	fwerror;
2289    static int	initted = 0;
2290
2291    debug_called(2);
2292
2293    /* first time around, clear any hardware completion status */
2294    if (!initted) {
2295	MLX_V3_PUT_IDBR(sc, MLX_V3_IDB_SACK);
2296	DELAY(1000);
2297	initted = 1;
2298    }
2299
2300    /* init in progress? */
2301    if (!(MLX_V3_GET_IDBR(sc) & MLX_V3_IDB_INIT_BUSY))
2302	return(0);
2303
2304    /* test error value */
2305    fwerror = MLX_V3_GET_FWERROR(sc);
2306    if (!(fwerror & MLX_V3_FWERROR_PEND))
2307	return(1);
2308
2309    /* mask status pending bit, fetch status */
2310    *error = fwerror & ~MLX_V3_FWERROR_PEND;
2311    *param1 = MLX_V3_GET_FWERROR_PARAM1(sc);
2312    *param2 = MLX_V3_GET_FWERROR_PARAM2(sc);
2313
2314    /* acknowledge */
2315    MLX_V3_PUT_FWERROR(sc, 0);
2316
2317    return(2);
2318}
2319
2320/********************************************************************************
2321 ********************************************************************************
2322                                                Type 4 interface accessor methods
2323 ********************************************************************************
2324 ********************************************************************************/
2325
2326/********************************************************************************
2327 * Try to give (mc) to the controller.  Returns 1 if successful, 0 on failure
2328 * (the controller is not ready to take a command).
2329 *
2330 * Must be called at splbio or in a fashion that prevents reentry.
2331 */
2332static int
2333mlx_v4_tryqueue(struct mlx_softc *sc, struct mlx_command *mc)
2334{
2335    int		i;
2336
2337    debug_called(2);
2338
2339    /* ready for our command? */
2340    if (!(MLX_V4_GET_IDBR(sc) & MLX_V4_IDB_FULL)) {
2341	/* copy mailbox data to window */
2342	for (i = 0; i < 13; i++)
2343	    MLX_V4_PUT_MAILBOX(sc, i, mc->mc_mailbox[i]);
2344
2345	/* memory-mapped controller, so issue a write barrier to ensure the mailbox is filled */
2346	bus_space_barrier(sc->mlx_btag, sc->mlx_bhandle, MLX_V4_MAILBOX, MLX_V4_MAILBOX_LENGTH,
2347			  BUS_SPACE_BARRIER_WRITE);
2348
2349	/* post command */
2350	MLX_V4_PUT_IDBR(sc, MLX_V4_IDB_HWMBOX_CMD);
2351	return(1);
2352    }
2353    return(0);
2354}
2355
2356/********************************************************************************
2357 * See if a command has been completed, if so acknowledge its completion
2358 * and recover the slot number and status code.
2359 *
2360 * Must be called at splbio or in a fashion that prevents reentry.
2361 */
2362static int
2363mlx_v4_findcomplete(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status)
2364{
2365
2366    debug_called(2);
2367
2368    /* status available? */
2369    if (MLX_V4_GET_ODBR(sc) & MLX_V4_ODB_HWSAVAIL) {
2370	*slot = MLX_V4_GET_STATUS_IDENT(sc);		/* get command identifier */
2371	*status = MLX_V4_GET_STATUS(sc);		/* get status */
2372
2373	/* acknowledge completion */
2374	MLX_V4_PUT_ODBR(sc, MLX_V4_ODB_HWMBOX_ACK);
2375	MLX_V4_PUT_IDBR(sc, MLX_V4_IDB_SACK);
2376	return(1);
2377    }
2378    return(0);
2379}
2380
2381/********************************************************************************
2382 * Enable/disable interrupts as requested.
2383 *
2384 * Must be called at splbio or in a fashion that prevents reentry.
2385 */
2386static void
2387mlx_v4_intaction(struct mlx_softc *sc, int action)
2388{
2389    debug_called(1);
2390
2391    switch(action) {
2392    case MLX_INTACTION_DISABLE:
2393	MLX_V4_PUT_IER(sc, MLX_V4_IER_MASK | MLX_V4_IER_DISINT);
2394	sc->mlx_state &= ~MLX_STATE_INTEN;
2395	break;
2396    case MLX_INTACTION_ENABLE:
2397	MLX_V4_PUT_IER(sc, MLX_V4_IER_MASK & ~MLX_V4_IER_DISINT);
2398	sc->mlx_state |= MLX_STATE_INTEN;
2399	break;
2400    }
2401}
2402
2403/********************************************************************************
2404 * Poll for firmware error codes during controller initialisation.
2405 * Returns 0 if initialisation is complete, 1 if still in progress but no
2406 * error has been fetched, 2 if an error has been retrieved.
2407 */
2408static int
2409mlx_v4_fw_handshake(struct mlx_softc *sc, int *error, int *param1, int *param2)
2410{
2411    u_int8_t	fwerror;
2412    static int	initted = 0;
2413
2414    debug_called(2);
2415
2416    /* first time around, clear any hardware completion status */
2417    if (!initted) {
2418	MLX_V4_PUT_IDBR(sc, MLX_V4_IDB_SACK);
2419	DELAY(1000);
2420	initted = 1;
2421    }
2422
2423    /* init in progress? */
2424    if (!(MLX_V4_GET_IDBR(sc) & MLX_V4_IDB_INIT_BUSY))
2425	return(0);
2426
2427    /* test error value */
2428    fwerror = MLX_V4_GET_FWERROR(sc);
2429    if (!(fwerror & MLX_V4_FWERROR_PEND))
2430	return(1);
2431
2432    /* mask status pending bit, fetch status */
2433    *error = fwerror & ~MLX_V4_FWERROR_PEND;
2434    *param1 = MLX_V4_GET_FWERROR_PARAM1(sc);
2435    *param2 = MLX_V4_GET_FWERROR_PARAM2(sc);
2436
2437    /* acknowledge */
2438    MLX_V4_PUT_FWERROR(sc, 0);
2439
2440    return(2);
2441}
2442
2443/********************************************************************************
2444 ********************************************************************************
2445                                                Type 5 interface accessor methods
2446 ********************************************************************************
2447 ********************************************************************************/
2448
2449/********************************************************************************
2450 * Try to give (mc) to the controller.  Returns 1 if successful, 0 on failure
2451 * (the controller is not ready to take a command).
2452 *
2453 * Must be called at splbio or in a fashion that prevents reentry.
2454 */
2455static int
2456mlx_v5_tryqueue(struct mlx_softc *sc, struct mlx_command *mc)
2457{
2458    int		i;
2459
2460    debug_called(2);
2461
2462    /* ready for our command? */
2463    if (MLX_V5_GET_IDBR(sc) & MLX_V5_IDB_EMPTY) {
2464	/* copy mailbox data to window */
2465	for (i = 0; i < 13; i++)
2466	    MLX_V5_PUT_MAILBOX(sc, i, mc->mc_mailbox[i]);
2467
2468	/* post command */
2469	MLX_V5_PUT_IDBR(sc, MLX_V5_IDB_HWMBOX_CMD);
2470	return(1);
2471    }
2472    return(0);
2473}
2474
2475/********************************************************************************
2476 * See if a command has been completed, if so acknowledge its completion
2477 * and recover the slot number and status code.
2478 *
2479 * Must be called at splbio or in a fashion that prevents reentry.
2480 */
2481static int
2482mlx_v5_findcomplete(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status)
2483{
2484
2485    debug_called(2);
2486
2487    /* status available? */
2488    if (MLX_V5_GET_ODBR(sc) & MLX_V5_ODB_HWSAVAIL) {
2489	*slot = MLX_V5_GET_STATUS_IDENT(sc);		/* get command identifier */
2490	*status = MLX_V5_GET_STATUS(sc);		/* get status */
2491
2492	/* acknowledge completion */
2493	MLX_V5_PUT_ODBR(sc, MLX_V5_ODB_HWMBOX_ACK);
2494	MLX_V5_PUT_IDBR(sc, MLX_V5_IDB_SACK);
2495	return(1);
2496    }
2497    return(0);
2498}
2499
2500/********************************************************************************
2501 * Enable/disable interrupts as requested.
2502 *
2503 * Must be called at splbio or in a fashion that prevents reentry.
2504 */
2505static void
2506mlx_v5_intaction(struct mlx_softc *sc, int action)
2507{
2508    debug_called(1);
2509
2510    switch(action) {
2511    case MLX_INTACTION_DISABLE:
2512	MLX_V5_PUT_IER(sc, 0xff & MLX_V5_IER_DISINT);
2513	sc->mlx_state &= ~MLX_STATE_INTEN;
2514	break;
2515    case MLX_INTACTION_ENABLE:
2516	MLX_V5_PUT_IER(sc, 0xff & ~MLX_V5_IER_DISINT);
2517	sc->mlx_state |= MLX_STATE_INTEN;
2518	break;
2519    }
2520}
2521
2522/********************************************************************************
2523 * Poll for firmware error codes during controller initialisation.
2524 * Returns 0 if initialisation is complete, 1 if still in progress but no
2525 * error has been fetched, 2 if an error has been retrieved.
2526 */
2527static int
2528mlx_v5_fw_handshake(struct mlx_softc *sc, int *error, int *param1, int *param2)
2529{
2530    u_int8_t	fwerror;
2531    static int	initted = 0;
2532
2533    debug_called(2);
2534
2535    /* first time around, clear any hardware completion status */
2536    if (!initted) {
2537	MLX_V5_PUT_IDBR(sc, MLX_V5_IDB_SACK);
2538	DELAY(1000);
2539	initted = 1;
2540    }
2541
2542    /* init in progress? */
2543    if (MLX_V5_GET_IDBR(sc) & MLX_V5_IDB_INIT_DONE)
2544	return(0);
2545
2546    /* test for error value */
2547    fwerror = MLX_V5_GET_FWERROR(sc);
2548    if (!(fwerror & MLX_V5_FWERROR_PEND))
2549	return(1);
2550
2551    /* mask status pending bit, fetch status */
2552    *error = fwerror & ~MLX_V5_FWERROR_PEND;
2553    *param1 = MLX_V5_GET_FWERROR_PARAM1(sc);
2554    *param2 = MLX_V5_GET_FWERROR_PARAM2(sc);
2555
2556    /* acknowledge */
2557    MLX_V5_PUT_FWERROR(sc, 0xff);
2558
2559    return(2);
2560}
2561
2562/********************************************************************************
2563 ********************************************************************************
2564                                                                        Debugging
2565 ********************************************************************************
2566 ********************************************************************************/
2567
2568/********************************************************************************
2569 * Return a status message describing (mc)
2570 */
2571static char *mlx_status_messages[] = {
2572    "normal completion",			/* 00 */
2573    "irrecoverable data error",			/* 01 */
2574    "drive does not exist, or is offline",	/* 02 */
2575    "attempt to write beyond end of drive",	/* 03 */
2576    "bad data encountered",			/* 04 */
2577    "invalid log entry request",		/* 05 */
2578    "attempt to rebuild online drive",		/* 06 */
2579    "new disk failed during rebuild",		/* 07 */
2580    "invalid channel/target",			/* 08 */
2581    "rebuild/check already in progress",	/* 09 */
2582    "one or more disks are dead",		/* 10 */
2583    "invalid or non-redundant drive",		/* 11 */
2584    "channel is busy",				/* 12 */
2585    "channel is not stopped",			/* 13 */
2586    "rebuild successfully terminated",		/* 14 */
2587    "unsupported command",			/* 15 */
2588    "check condition received",			/* 16 */
2589    "device is busy",				/* 17 */
2590    "selection or command timeout",		/* 18 */
2591    "command terminated abnormally",		/* 19 */
2592    ""
2593};
2594
2595static struct
2596{
2597    int		command;
2598    u_int16_t	status;
2599    int		msg;
2600} mlx_messages[] = {
2601    {MLX_CMD_READSG,		0x0001,	 1},
2602    {MLX_CMD_READSG,		0x0002,	 1},
2603    {MLX_CMD_READSG,		0x0105,	 3},
2604    {MLX_CMD_READSG,		0x010c,	 4},
2605    {MLX_CMD_WRITESG,		0x0001,	 1},
2606    {MLX_CMD_WRITESG,		0x0002,	 1},
2607    {MLX_CMD_WRITESG,		0x0105,	 3},
2608    {MLX_CMD_READSG_OLD,	0x0001,	 1},
2609    {MLX_CMD_READSG_OLD,	0x0002,	 1},
2610    {MLX_CMD_READSG_OLD,	0x0105,	 3},
2611    {MLX_CMD_WRITESG_OLD,	0x0001,	 1},
2612    {MLX_CMD_WRITESG_OLD,	0x0002,	 1},
2613    {MLX_CMD_WRITESG_OLD,	0x0105,	 3},
2614    {MLX_CMD_LOGOP,		0x0105,	 5},
2615    {MLX_CMD_REBUILDASYNC,	0x0002,  6},
2616    {MLX_CMD_REBUILDASYNC,	0x0004,  7},
2617    {MLX_CMD_REBUILDASYNC,	0x0105,  8},
2618    {MLX_CMD_REBUILDASYNC,	0x0106,  9},
2619    {MLX_CMD_REBUILDASYNC,	0x0107, 14},
2620    {MLX_CMD_CHECKASYNC,	0x0002, 10},
2621    {MLX_CMD_CHECKASYNC,	0x0105, 11},
2622    {MLX_CMD_CHECKASYNC,	0x0106,  9},
2623    {MLX_CMD_STOPCHANNEL,	0x0106, 12},
2624    {MLX_CMD_STOPCHANNEL,	0x0105,  8},
2625    {MLX_CMD_STARTCHANNEL,	0x0005, 13},
2626    {MLX_CMD_STARTCHANNEL,	0x0105,  8},
2627    {MLX_CMD_DIRECT_CDB,	0x0002, 16},
2628    {MLX_CMD_DIRECT_CDB,	0x0008, 17},
2629    {MLX_CMD_DIRECT_CDB,	0x000e, 18},
2630    {MLX_CMD_DIRECT_CDB,	0x000f, 19},
2631    {MLX_CMD_DIRECT_CDB,	0x0105,  8},
2632
2633    {0,				0x0104, 14},
2634    {-1, 0, 0}
2635};
2636
2637static char *
2638mlx_diagnose_command(struct mlx_command *mc)
2639{
2640    static char	unkmsg[80];
2641    int		i;
2642
2643    /* look up message in table */
2644    for (i = 0; mlx_messages[i].command != -1; i++)
2645	if (((mc->mc_mailbox[0] == mlx_messages[i].command) || (mlx_messages[i].command == 0)) &&
2646	    (mc->mc_status == mlx_messages[i].status))
2647	    return(mlx_status_messages[mlx_messages[i].msg]);
2648
2649    sprintf(unkmsg, "unknown response 0x%x for command 0x%x", (int)mc->mc_status, (int)mc->mc_mailbox[0]);
2650    return(unkmsg);
2651}
2652
2653/*******************************************************************************
2654 * Print a string describing the controller (sc)
2655 */
2656static struct
2657{
2658    int		hwid;
2659    char	*name;
2660} mlx_controller_names[] = {
2661    {0x01,	"960P/PD"},
2662    {0x02,	"960PL"},
2663    {0x10,	"960PG"},
2664    {0x11,	"960PJ"},
2665    {0x12,	"960PR"},
2666    {0x13,	"960PT"},
2667    {0x14,	"960PTL0"},
2668    {0x15,	"960PRL"},
2669    {0x16,	"960PTL1"},
2670    {0x20,	"1164PVX"},
2671    {-1, NULL}
2672};
2673
2674static void
2675mlx_describe_controller(struct mlx_softc *sc)
2676{
2677    static char		buf[80];
2678    char		*model;
2679    int			i;
2680
2681    for (i = 0, model = NULL; mlx_controller_names[i].name != NULL; i++) {
2682	if ((sc->mlx_enq2->me_hardware_id & 0xff) == mlx_controller_names[i].hwid) {
2683	    model = mlx_controller_names[i].name;
2684	    break;
2685	}
2686    }
2687    if (model == NULL) {
2688	sprintf(buf, " model 0x%x", sc->mlx_enq2->me_hardware_id & 0xff);
2689	model = buf;
2690    }
2691    device_printf(sc->mlx_dev, "DAC%s, %d channel%s, firmware %d.%02d-%c-%02d, %dMB RAM\n",
2692		  model,
2693		  sc->mlx_enq2->me_actual_channels,
2694		  sc->mlx_enq2->me_actual_channels > 1 ? "s" : "",
2695		  sc->mlx_enq2->me_firmware_id & 0xff,
2696		  (sc->mlx_enq2->me_firmware_id >> 8) & 0xff,
2697		  (sc->mlx_enq2->me_firmware_id >> 24) & 0xff,
2698		  (sc->mlx_enq2->me_firmware_id >> 16) & 0xff,
2699		  sc->mlx_enq2->me_mem_size / (1024 * 1024));
2700
2701    if (bootverbose) {
2702	device_printf(sc->mlx_dev, "  Hardware ID                 0x%08x\n", sc->mlx_enq2->me_hardware_id);
2703	device_printf(sc->mlx_dev, "  Firmware ID                 0x%08x\n", sc->mlx_enq2->me_firmware_id);
2704	device_printf(sc->mlx_dev, "  Configured/Actual channels  %d/%d\n", sc->mlx_enq2->me_configured_channels,
2705		      sc->mlx_enq2->me_actual_channels);
2706	device_printf(sc->mlx_dev, "  Max Targets                 %d\n", sc->mlx_enq2->me_max_targets);
2707	device_printf(sc->mlx_dev, "  Max Tags                    %d\n", sc->mlx_enq2->me_max_tags);
2708	device_printf(sc->mlx_dev, "  Max System Drives           %d\n", sc->mlx_enq2->me_max_sys_drives);
2709	device_printf(sc->mlx_dev, "  Max Arms                    %d\n", sc->mlx_enq2->me_max_arms);
2710	device_printf(sc->mlx_dev, "  Max Spans                   %d\n", sc->mlx_enq2->me_max_spans);
2711	device_printf(sc->mlx_dev, "  DRAM/cache/flash/NVRAM size %d/%d/%d/%d\n", sc->mlx_enq2->me_mem_size,
2712		      sc->mlx_enq2->me_cache_size, sc->mlx_enq2->me_flash_size, sc->mlx_enq2->me_nvram_size);
2713	device_printf(sc->mlx_dev, "  DRAM type                   %d\n", sc->mlx_enq2->me_mem_type);
2714	device_printf(sc->mlx_dev, "  Clock Speed                 %dns\n", sc->mlx_enq2->me_clock_speed);
2715	device_printf(sc->mlx_dev, "  Hardware Speed              %dns\n", sc->mlx_enq2->me_hardware_speed);
2716	device_printf(sc->mlx_dev, "  Max Commands                %d\n", sc->mlx_enq2->me_max_commands);
2717	device_printf(sc->mlx_dev, "  Max SG Entries              %d\n", sc->mlx_enq2->me_max_sg);
2718	device_printf(sc->mlx_dev, "  Max DP                      %d\n", sc->mlx_enq2->me_max_dp);
2719	device_printf(sc->mlx_dev, "  Max IOD                     %d\n", sc->mlx_enq2->me_max_iod);
2720	device_printf(sc->mlx_dev, "  Max Comb                    %d\n", sc->mlx_enq2->me_max_comb);
2721	device_printf(sc->mlx_dev, "  Latency                     %ds\n", sc->mlx_enq2->me_latency);
2722	device_printf(sc->mlx_dev, "  SCSI Timeout                %ds\n", sc->mlx_enq2->me_scsi_timeout);
2723	device_printf(sc->mlx_dev, "  Min Free Lines              %d\n", sc->mlx_enq2->me_min_freelines);
2724	device_printf(sc->mlx_dev, "  Rate Constant               %d\n", sc->mlx_enq2->me_rate_const);
2725	device_printf(sc->mlx_dev, "  MAXBLK                      %d\n", sc->mlx_enq2->me_maxblk);
2726	device_printf(sc->mlx_dev, "  Blocking Factor             %d sectors\n", sc->mlx_enq2->me_blocking_factor);
2727	device_printf(sc->mlx_dev, "  Cache Line Size             %d blocks\n", sc->mlx_enq2->me_cacheline);
2728	device_printf(sc->mlx_dev, "  SCSI Capability             %s%dMHz, %d bit\n",
2729		      sc->mlx_enq2->me_scsi_cap & (1<<4) ? "differential " : "",
2730		      (1 << ((sc->mlx_enq2->me_scsi_cap >> 2) & 3)) * 10,
2731		      8 << (sc->mlx_enq2->me_scsi_cap & 0x3));
2732	device_printf(sc->mlx_dev, "  Firmware Build Number       %d\n", sc->mlx_enq2->me_firmware_build);
2733	device_printf(sc->mlx_dev, "  Fault Management Type       %d\n", sc->mlx_enq2->me_fault_mgmt_type);
2734	device_printf(sc->mlx_dev, "  Features                    %b\n", sc->mlx_enq2->me_firmware_features,
2735		      "\20\4Background Init\3Read Ahead\2MORE\1Cluster\n");
2736
2737    }
2738}
2739
2740/*******************************************************************************
2741 * Emit a string describing the firmware handshake status code, and return a flag
2742 * indicating whether the code represents a fatal error.
2743 *
2744 * Error code interpretations are from the Linux driver, and don't directly match
2745 * the messages printed by Mylex's BIOS.  This may change if documentation on the
2746 * codes is forthcoming.
2747 */
2748static int
2749mlx_fw_message(struct mlx_softc *sc, int error, int param1, int param2)
2750{
2751    switch(error) {
2752    case 0x00:
2753	device_printf(sc->mlx_dev, "physical drive %d:%d not responding\n", param2, param1);
2754	break;
2755    case 0x08:
2756	/* we could be neater about this and give some indication when we receive more of them */
2757	if (!(sc->mlx_flags & MLX_SPINUP_REPORTED)) {
2758	    device_printf(sc->mlx_dev, "spinning up drives...\n");
2759	    sc->mlx_flags |= MLX_SPINUP_REPORTED;
2760	}
2761	break;
2762    case 0x30:
2763	device_printf(sc->mlx_dev, "configuration checksum error\n");
2764	break;
2765    case 0x60:
2766	device_printf(sc->mlx_dev, "mirror race recovery failed\n");
2767	break;
2768    case 0x70:
2769	device_printf(sc->mlx_dev, "mirror race recovery in progress\n");
2770	break;
2771    case 0x90:
2772	device_printf(sc->mlx_dev, "physical drive %d:%d COD mismatch\n", param2, param1);
2773	break;
2774    case 0xa0:
2775	device_printf(sc->mlx_dev, "logical drive installation aborted\n");
2776	break;
2777    case 0xb0:
2778	device_printf(sc->mlx_dev, "mirror race on a critical system drive\n");
2779	break;
2780    case 0xd0:
2781	device_printf(sc->mlx_dev, "new controller configuration found\n");
2782	break;
2783    case 0xf0:
2784	device_printf(sc->mlx_dev, "FATAL MEMORY PARITY ERROR\n");
2785	return(1);
2786    default:
2787	device_printf(sc->mlx_dev, "unknown firmware initialisation error %02x:%02x:%02x\n", error, param1, param2);
2788	break;
2789    }
2790    return(0);
2791}
2792
2793/********************************************************************************
2794 ********************************************************************************
2795                                                                Utility Functions
2796 ********************************************************************************
2797 ********************************************************************************/
2798
2799/********************************************************************************
2800 * Find the disk whose unit number is (unit) on this controller
2801 */
2802static struct mlx_sysdrive *
2803mlx_findunit(struct mlx_softc *sc, int unit)
2804{
2805    int		i;
2806
2807    /* search system drives */
2808    for (i = 0; i < MLX_MAXDRIVES; i++) {
2809	/* is this one attached? */
2810	if (sc->mlx_sysdrive[i].ms_disk != 0) {
2811	    /* is this the one? */
2812	    if (unit == device_get_unit(sc->mlx_sysdrive[i].ms_disk))
2813		return(&sc->mlx_sysdrive[i]);
2814	}
2815    }
2816    return(NULL);
2817}
2818