11ac4b82bSMike Smith /*- 21ac4b82bSMike Smith * Copyright (c) 1999 Michael Smith 31ac4b82bSMike Smith * All rights reserved. 41ac4b82bSMike Smith * 51ac4b82bSMike Smith * Redistribution and use in source and binary forms, with or without 61ac4b82bSMike Smith * modification, are permitted provided that the following conditions 71ac4b82bSMike Smith * are met: 81ac4b82bSMike Smith * 1. Redistributions of source code must retain the above copyright 91ac4b82bSMike Smith * notice, this list of conditions and the following disclaimer. 101ac4b82bSMike Smith * 2. Redistributions in binary form must reproduce the above copyright 111ac4b82bSMike Smith * notice, this list of conditions and the following disclaimer in the 121ac4b82bSMike Smith * documentation and/or other materials provided with the distribution. 131ac4b82bSMike Smith * 141ac4b82bSMike Smith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 151ac4b82bSMike Smith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 161ac4b82bSMike Smith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 171ac4b82bSMike Smith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 181ac4b82bSMike Smith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 191ac4b82bSMike Smith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 201ac4b82bSMike Smith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 211ac4b82bSMike Smith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 221ac4b82bSMike Smith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 231ac4b82bSMike Smith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 241ac4b82bSMike Smith * SUCH DAMAGE. 251ac4b82bSMike Smith * 261ac4b82bSMike Smith * $FreeBSD$ 271ac4b82bSMike Smith */ 281ac4b82bSMike Smith 291ac4b82bSMike Smith /* 301ac4b82bSMike Smith * Driver for the Mylex DAC960 family of RAID controllers. 311ac4b82bSMike Smith */ 321ac4b82bSMike Smith 331ac4b82bSMike Smith #include <sys/param.h> 341ac4b82bSMike Smith #include <sys/systm.h> 35b04e4c12SJohn Baldwin #include <sys/bio.h> 360fca6f8bSJohn Baldwin #include <sys/lock.h> 371ac4b82bSMike Smith #include <sys/malloc.h> 380fca6f8bSJohn Baldwin #include <sys/mutex.h> 391ac4b82bSMike Smith #include <sys/kernel.h> 400fca6f8bSJohn Baldwin #include <sys/sx.h> 411ac4b82bSMike Smith 421ac4b82bSMike Smith #include <sys/bus.h> 431ac4b82bSMike Smith #include <sys/conf.h> 44da8bb3a3SMike Smith #include <sys/stat.h> 451ac4b82bSMike Smith 461ac4b82bSMike Smith #include <machine/resource.h> 471ac4b82bSMike Smith #include <machine/bus.h> 481ac4b82bSMike Smith #include <machine/clock.h> 491ac4b82bSMike Smith #include <sys/rman.h> 501ac4b82bSMike Smith 51891619a6SPoul-Henning Kamp #include <geom/geom_disk.h> 52891619a6SPoul-Henning Kamp 531ac4b82bSMike Smith #include <dev/mlx/mlxio.h> 541ac4b82bSMike Smith #include <dev/mlx/mlxvar.h> 551ac4b82bSMike Smith #include <dev/mlx/mlxreg.h> 561ac4b82bSMike Smith 571ac4b82bSMike Smith static struct cdevsw mlx_cdevsw = { 58dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 597ac40f5fSPoul-Henning Kamp .d_open = mlx_open, 607ac40f5fSPoul-Henning Kamp .d_close = mlx_close, 617ac40f5fSPoul-Henning Kamp .d_ioctl = mlx_ioctl, 627ac40f5fSPoul-Henning Kamp .d_name = "mlx", 631ac4b82bSMike Smith }; 641ac4b82bSMike Smith 651ac4b82bSMike Smith devclass_t mlx_devclass; 661ac4b82bSMike Smith 671ac4b82bSMike Smith /* 681ac4b82bSMike Smith * Per-interface accessor methods 691ac4b82bSMike Smith */ 701ac4b82bSMike Smith static int mlx_v3_tryqueue(struct mlx_softc *sc, struct mlx_command *mc); 711ac4b82bSMike Smith static int mlx_v3_findcomplete(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status); 721ac4b82bSMike Smith static void mlx_v3_intaction(struct mlx_softc *sc, int action); 730fca6f8bSJohn Baldwin static int mlx_v3_fw_handshake(struct mlx_softc *sc, int *error, int *param1, int *param2, int first); 741ac4b82bSMike Smith 75f6b84b08SMike Smith static int mlx_v4_tryqueue(struct mlx_softc *sc, struct mlx_command *mc); 76f6b84b08SMike Smith static int mlx_v4_findcomplete(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status); 77f6b84b08SMike Smith static void mlx_v4_intaction(struct mlx_softc *sc, int action); 780fca6f8bSJohn Baldwin static int mlx_v4_fw_handshake(struct mlx_softc *sc, int *error, int *param1, int *param2, int first); 79f6b84b08SMike Smith 805792b7feSMike Smith static int mlx_v5_tryqueue(struct mlx_softc *sc, struct mlx_command *mc); 815792b7feSMike Smith static int mlx_v5_findcomplete(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status); 825792b7feSMike Smith static void mlx_v5_intaction(struct mlx_softc *sc, int action); 830fca6f8bSJohn Baldwin static int mlx_v5_fw_handshake(struct mlx_softc *sc, int *error, int *param1, int *param2, int first); 845792b7feSMike Smith 851ac4b82bSMike Smith /* 861ac4b82bSMike Smith * Status monitoring 871ac4b82bSMike Smith */ 881ac4b82bSMike Smith static void mlx_periodic(void *data); 891ac4b82bSMike Smith static void mlx_periodic_enquiry(struct mlx_command *mc); 901ac4b82bSMike Smith static void mlx_periodic_eventlog_poll(struct mlx_softc *sc); 911ac4b82bSMike Smith static void mlx_periodic_eventlog_respond(struct mlx_command *mc); 921ac4b82bSMike Smith static void mlx_periodic_rebuild(struct mlx_command *mc); 931ac4b82bSMike Smith 941ac4b82bSMike Smith /* 951ac4b82bSMike Smith * Channel Pause 961ac4b82bSMike Smith */ 971ac4b82bSMike Smith static void mlx_pause_action(struct mlx_softc *sc); 981ac4b82bSMike Smith static void mlx_pause_done(struct mlx_command *mc); 991ac4b82bSMike Smith 1001ac4b82bSMike Smith /* 1011ac4b82bSMike Smith * Command submission. 1021ac4b82bSMike Smith */ 1031ac4b82bSMike Smith static void *mlx_enquire(struct mlx_softc *sc, int command, size_t bufsize, 1041ac4b82bSMike Smith void (*complete)(struct mlx_command *mc)); 1051ac4b82bSMike Smith static int mlx_flush(struct mlx_softc *sc); 106421f2f7dSMike Smith static int mlx_check(struct mlx_softc *sc, int drive); 1071ac4b82bSMike Smith static int mlx_rebuild(struct mlx_softc *sc, int channel, int target); 1081ac4b82bSMike Smith static int mlx_wait_command(struct mlx_command *mc); 1091ac4b82bSMike Smith static int mlx_poll_command(struct mlx_command *mc); 1101b4404f9SScott Long void mlx_startio_cb(void *arg, 1111b4404f9SScott Long bus_dma_segment_t *segs, 1121b4404f9SScott Long int nsegments, int error); 1131ac4b82bSMike Smith static void mlx_startio(struct mlx_softc *sc); 1141ac4b82bSMike Smith static void mlx_completeio(struct mlx_command *mc); 1151b4404f9SScott Long static int mlx_user_command(struct mlx_softc *sc, 1161b4404f9SScott Long struct mlx_usercommand *mu); 1171b4404f9SScott Long void mlx_user_cb(void *arg, bus_dma_segment_t *segs, 1181b4404f9SScott Long int nsegments, int error); 1191ac4b82bSMike Smith 1201ac4b82bSMike Smith /* 1211ac4b82bSMike Smith * Command buffer allocation. 1221ac4b82bSMike Smith */ 1231ac4b82bSMike Smith static struct mlx_command *mlx_alloccmd(struct mlx_softc *sc); 1241ac4b82bSMike Smith static void mlx_releasecmd(struct mlx_command *mc); 1251ac4b82bSMike Smith static void mlx_freecmd(struct mlx_command *mc); 1261ac4b82bSMike Smith 1271ac4b82bSMike Smith /* 1281ac4b82bSMike Smith * Command management. 1291ac4b82bSMike Smith */ 1301ac4b82bSMike Smith static int mlx_getslot(struct mlx_command *mc); 1311b4404f9SScott Long static void mlx_setup_dmamap(struct mlx_command *mc, 1321b4404f9SScott Long bus_dma_segment_t *segs, 1331b4404f9SScott Long int nsegments, int error); 1341ac4b82bSMike Smith static void mlx_unmapcmd(struct mlx_command *mc); 1350fca6f8bSJohn Baldwin static int mlx_shutdown_locked(struct mlx_softc *sc); 1361ac4b82bSMike Smith static int mlx_start(struct mlx_command *mc); 1370fca6f8bSJohn Baldwin static int mlx_done(struct mlx_softc *sc, int startio); 1381ac4b82bSMike Smith static void mlx_complete(struct mlx_softc *sc); 1391ac4b82bSMike Smith 1401ac4b82bSMike Smith /* 1411ac4b82bSMike Smith * Debugging. 1421ac4b82bSMike Smith */ 1431ac4b82bSMike Smith static char *mlx_diagnose_command(struct mlx_command *mc); 1449eee27f1SMike Smith static void mlx_describe_controller(struct mlx_softc *sc); 145da8bb3a3SMike Smith static int mlx_fw_message(struct mlx_softc *sc, int status, int param1, int param2); 1461ac4b82bSMike Smith 1471ac4b82bSMike Smith /* 1481ac4b82bSMike Smith * Utility functions. 1491ac4b82bSMike Smith */ 1501ac4b82bSMike Smith static struct mlx_sysdrive *mlx_findunit(struct mlx_softc *sc, int unit); 1511ac4b82bSMike Smith 1521ac4b82bSMike Smith /******************************************************************************** 1531ac4b82bSMike Smith ******************************************************************************** 1541ac4b82bSMike Smith Public Interfaces 1551ac4b82bSMike Smith ******************************************************************************** 1561ac4b82bSMike Smith ********************************************************************************/ 1571ac4b82bSMike Smith 1581ac4b82bSMike Smith /******************************************************************************** 1591ac4b82bSMike Smith * Free all of the resources associated with (sc) 1601ac4b82bSMike Smith * 1611ac4b82bSMike Smith * Should not be called if the controller is active. 1621ac4b82bSMike Smith */ 1631ac4b82bSMike Smith void 1641ac4b82bSMike Smith mlx_free(struct mlx_softc *sc) 1651ac4b82bSMike Smith { 1661ac4b82bSMike Smith struct mlx_command *mc; 1671ac4b82bSMike Smith 168da8bb3a3SMike Smith debug_called(1); 1691ac4b82bSMike Smith 1700fca6f8bSJohn Baldwin /* destroy control device */ 1710fca6f8bSJohn Baldwin if (sc->mlx_dev_t != NULL) 1720fca6f8bSJohn Baldwin destroy_dev(sc->mlx_dev_t); 1730fca6f8bSJohn Baldwin 1740fca6f8bSJohn Baldwin if (sc->mlx_intr) 1750fca6f8bSJohn Baldwin bus_teardown_intr(sc->mlx_dev, sc->mlx_irq, sc->mlx_intr); 1760fca6f8bSJohn Baldwin 1771ac4b82bSMike Smith /* cancel status timeout */ 1780fca6f8bSJohn Baldwin MLX_IO_LOCK(sc); 1790fca6f8bSJohn Baldwin callout_stop(&sc->mlx_timeout); 1801ac4b82bSMike Smith 1811ac4b82bSMike Smith /* throw away any command buffers */ 1821ac4b82bSMike Smith while ((mc = TAILQ_FIRST(&sc->mlx_freecmds)) != NULL) { 1831ac4b82bSMike Smith TAILQ_REMOVE(&sc->mlx_freecmds, mc, mc_link); 1841ac4b82bSMike Smith mlx_freecmd(mc); 1851ac4b82bSMike Smith } 1860fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc); 1870fca6f8bSJohn Baldwin callout_drain(&sc->mlx_timeout); 1881ac4b82bSMike Smith 1891ac4b82bSMike Smith /* destroy data-transfer DMA tag */ 1901ac4b82bSMike Smith if (sc->mlx_buffer_dmat) 1911ac4b82bSMike Smith bus_dma_tag_destroy(sc->mlx_buffer_dmat); 1921ac4b82bSMike Smith 1931ac4b82bSMike Smith /* free and destroy DMA memory and tag for s/g lists */ 194aced5239SJohn Baldwin if (sc->mlx_sgbusaddr) 195aced5239SJohn Baldwin bus_dmamap_unload(sc->mlx_sg_dmat, sc->mlx_sg_dmamap); 1961ac4b82bSMike Smith if (sc->mlx_sgtable) 1971ac4b82bSMike Smith bus_dmamem_free(sc->mlx_sg_dmat, sc->mlx_sgtable, sc->mlx_sg_dmamap); 1981ac4b82bSMike Smith if (sc->mlx_sg_dmat) 1991ac4b82bSMike Smith bus_dma_tag_destroy(sc->mlx_sg_dmat); 2001ac4b82bSMike Smith 2011ac4b82bSMike Smith /* disconnect the interrupt handler */ 2021ac4b82bSMike Smith if (sc->mlx_irq != NULL) 2031ac4b82bSMike Smith bus_release_resource(sc->mlx_dev, SYS_RES_IRQ, 0, sc->mlx_irq); 2041ac4b82bSMike Smith 2051ac4b82bSMike Smith /* destroy the parent DMA tag */ 2061ac4b82bSMike Smith if (sc->mlx_parent_dmat) 2071ac4b82bSMike Smith bus_dma_tag_destroy(sc->mlx_parent_dmat); 2081ac4b82bSMike Smith 2091ac4b82bSMike Smith /* release the register window mapping */ 2101ac4b82bSMike Smith if (sc->mlx_mem != NULL) 2119b11c7baSMatthew N. Dodd bus_release_resource(sc->mlx_dev, sc->mlx_mem_type, sc->mlx_mem_rid, sc->mlx_mem); 2129eee27f1SMike Smith 2139eee27f1SMike Smith /* free controller enquiry data */ 2149eee27f1SMike Smith if (sc->mlx_enq2 != NULL) 2159eee27f1SMike Smith free(sc->mlx_enq2, M_DEVBUF); 216da8bb3a3SMike Smith 2170fca6f8bSJohn Baldwin sx_destroy(&sc->mlx_config_lock); 2180fca6f8bSJohn Baldwin mtx_destroy(&sc->mlx_io_lock); 2191ac4b82bSMike Smith } 2201ac4b82bSMike Smith 2211ac4b82bSMike Smith /******************************************************************************** 2221ac4b82bSMike Smith * Map the scatter/gather table into bus space 2231ac4b82bSMike Smith */ 2241ac4b82bSMike Smith static void 2251ac4b82bSMike Smith mlx_dma_map_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 2261ac4b82bSMike Smith { 2271ac4b82bSMike Smith struct mlx_softc *sc = (struct mlx_softc *)arg; 2281ac4b82bSMike Smith 229da8bb3a3SMike Smith debug_called(1); 2301ac4b82bSMike Smith 2311ac4b82bSMike Smith /* save base of s/g table's address in bus space */ 2321ac4b82bSMike Smith sc->mlx_sgbusaddr = segs->ds_addr; 2331ac4b82bSMike Smith } 2341ac4b82bSMike Smith 2351ac4b82bSMike Smith static int 2361ac4b82bSMike Smith mlx_sglist_map(struct mlx_softc *sc) 2371ac4b82bSMike Smith { 2381ac4b82bSMike Smith size_t segsize; 239baff09dbSMike Smith int error, ncmd; 2401ac4b82bSMike Smith 241da8bb3a3SMike Smith debug_called(1); 2421ac4b82bSMike Smith 2431ac4b82bSMike Smith /* destroy any existing mappings */ 244aced5239SJohn Baldwin if (sc->mlx_sgbusaddr) 245aced5239SJohn Baldwin bus_dmamap_unload(sc->mlx_sg_dmat, sc->mlx_sg_dmamap); 2461ac4b82bSMike Smith if (sc->mlx_sgtable) 2471ac4b82bSMike Smith bus_dmamem_free(sc->mlx_sg_dmat, sc->mlx_sgtable, sc->mlx_sg_dmamap); 2481ac4b82bSMike Smith if (sc->mlx_sg_dmat) 2491ac4b82bSMike Smith bus_dma_tag_destroy(sc->mlx_sg_dmat); 250aced5239SJohn Baldwin sc->mlx_sgbusaddr = 0; 251aced5239SJohn Baldwin sc->mlx_sgtable = NULL; 252aced5239SJohn Baldwin sc->mlx_sg_dmat = NULL; 2531ac4b82bSMike Smith 2541ac4b82bSMike Smith /* 2551ac4b82bSMike Smith * Create a single tag describing a region large enough to hold all of 256baff09dbSMike Smith * the s/g lists we will need. If we're called early on, we don't know how 257baff09dbSMike Smith * many commands we're going to be asked to support, so only allocate enough 258baff09dbSMike Smith * for a couple. 2591ac4b82bSMike Smith */ 260baff09dbSMike Smith if (sc->mlx_enq2 == NULL) { 261baff09dbSMike Smith ncmd = 2; 262baff09dbSMike Smith } else { 263baff09dbSMike Smith ncmd = sc->mlx_enq2->me_max_commands; 264baff09dbSMike Smith } 265baff09dbSMike Smith segsize = sizeof(struct mlx_sgentry) * MLX_NSEG * ncmd; 2661ac4b82bSMike Smith error = bus_dma_tag_create(sc->mlx_parent_dmat, /* parent */ 2671ac4b82bSMike Smith 1, 0, /* alignment,boundary */ 2681ac4b82bSMike Smith BUS_SPACE_MAXADDR, /* lowaddr */ 2691ac4b82bSMike Smith BUS_SPACE_MAXADDR, /* highaddr */ 2701ac4b82bSMike Smith NULL, NULL, /* filter, filterarg */ 2711ac4b82bSMike Smith segsize, 1, /* maxsize, nsegments */ 2721ac4b82bSMike Smith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 2731ac4b82bSMike Smith 0, /* flags */ 274fc3e87b3SScott Long NULL, NULL, /* lockfunc, lockarg */ 2751ac4b82bSMike Smith &sc->mlx_sg_dmat); 2761ac4b82bSMike Smith if (error != 0) { 2771ac4b82bSMike Smith device_printf(sc->mlx_dev, "can't allocate scatter/gather DMA tag\n"); 2781ac4b82bSMike Smith return(ENOMEM); 2791ac4b82bSMike Smith } 2801ac4b82bSMike Smith 2811ac4b82bSMike Smith /* 2821ac4b82bSMike Smith * Allocate enough s/g maps for all commands and permanently map them into 2831ac4b82bSMike Smith * controller-visible space. 2841ac4b82bSMike Smith * 2851ac4b82bSMike Smith * XXX this assumes we can get enough space for all the s/g maps in one 286fc3e87b3SScott Long * contiguous slab. We may need to switch to a more complex arrangement 287fc3e87b3SScott Long * where we allocate in smaller chunks and keep a lookup table from slot 288fc3e87b3SScott Long * to bus address. 2891ac4b82bSMike Smith */ 290fc3e87b3SScott Long error = bus_dmamem_alloc(sc->mlx_sg_dmat, (void **)&sc->mlx_sgtable, 291fc3e87b3SScott Long BUS_DMA_NOWAIT, &sc->mlx_sg_dmamap); 2921ac4b82bSMike Smith if (error) { 2931ac4b82bSMike Smith device_printf(sc->mlx_dev, "can't allocate s/g table\n"); 2941ac4b82bSMike Smith return(ENOMEM); 2951ac4b82bSMike Smith } 2961b4404f9SScott Long (void)bus_dmamap_load(sc->mlx_sg_dmat, sc->mlx_sg_dmamap, sc->mlx_sgtable, 297fc3e87b3SScott Long segsize, mlx_dma_map_sg, sc, 0); 2981ac4b82bSMike Smith return(0); 2991ac4b82bSMike Smith } 3001ac4b82bSMike Smith 3011ac4b82bSMike Smith /******************************************************************************** 3021ac4b82bSMike Smith * Initialise the controller and softc 3031ac4b82bSMike Smith */ 3041ac4b82bSMike Smith int 3051ac4b82bSMike Smith mlx_attach(struct mlx_softc *sc) 3061ac4b82bSMike Smith { 307da8bb3a3SMike Smith struct mlx_enquiry_old *meo; 308da8bb3a3SMike Smith int rid, error, fwminor, hscode, hserror, hsparam1, hsparam2, hsmsg; 3091ac4b82bSMike Smith 310da8bb3a3SMike Smith debug_called(1); 3111ac4b82bSMike Smith 3121ac4b82bSMike Smith /* 3131ac4b82bSMike Smith * Initialise per-controller queues. 3141ac4b82bSMike Smith */ 3154b006d7bSMike Smith TAILQ_INIT(&sc->mlx_work); 3161ac4b82bSMike Smith TAILQ_INIT(&sc->mlx_freecmds); 317b04e4c12SJohn Baldwin bioq_init(&sc->mlx_bioq); 3181ac4b82bSMike Smith 3191ac4b82bSMike Smith /* 3201ac4b82bSMike Smith * Select accessor methods based on controller interface type. 3211ac4b82bSMike Smith */ 3221ac4b82bSMike Smith switch(sc->mlx_iftype) { 323da8bb3a3SMike Smith case MLX_IFTYPE_2: 3241ac4b82bSMike Smith case MLX_IFTYPE_3: 3251ac4b82bSMike Smith sc->mlx_tryqueue = mlx_v3_tryqueue; 3261ac4b82bSMike Smith sc->mlx_findcomplete = mlx_v3_findcomplete; 3271ac4b82bSMike Smith sc->mlx_intaction = mlx_v3_intaction; 328da8bb3a3SMike Smith sc->mlx_fw_handshake = mlx_v3_fw_handshake; 3291ac4b82bSMike Smith break; 330f6b84b08SMike Smith case MLX_IFTYPE_4: 331f6b84b08SMike Smith sc->mlx_tryqueue = mlx_v4_tryqueue; 332f6b84b08SMike Smith sc->mlx_findcomplete = mlx_v4_findcomplete; 333f6b84b08SMike Smith sc->mlx_intaction = mlx_v4_intaction; 334da8bb3a3SMike Smith sc->mlx_fw_handshake = mlx_v4_fw_handshake; 335f6b84b08SMike Smith break; 3365792b7feSMike Smith case MLX_IFTYPE_5: 3375792b7feSMike Smith sc->mlx_tryqueue = mlx_v5_tryqueue; 3385792b7feSMike Smith sc->mlx_findcomplete = mlx_v5_findcomplete; 3395792b7feSMike Smith sc->mlx_intaction = mlx_v5_intaction; 340da8bb3a3SMike Smith sc->mlx_fw_handshake = mlx_v5_fw_handshake; 3415792b7feSMike Smith break; 3421ac4b82bSMike Smith default: 3431ac4b82bSMike Smith return(ENXIO); /* should never happen */ 3441ac4b82bSMike Smith } 3451ac4b82bSMike Smith 3461ac4b82bSMike Smith /* disable interrupts before we start talking to the controller */ 3470fca6f8bSJohn Baldwin MLX_IO_LOCK(sc); 3481ac4b82bSMike Smith sc->mlx_intaction(sc, MLX_INTACTION_DISABLE); 3490fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc); 3501ac4b82bSMike Smith 3511ac4b82bSMike Smith /* 352da8bb3a3SMike Smith * Wait for the controller to come ready, handshake with the firmware if required. 353da8bb3a3SMike Smith * This is typically only necessary on platforms where the controller BIOS does not 354da8bb3a3SMike Smith * run. 355da8bb3a3SMike Smith */ 356da8bb3a3SMike Smith hsmsg = 0; 357da8bb3a3SMike Smith DELAY(1000); 3580fca6f8bSJohn Baldwin while ((hscode = sc->mlx_fw_handshake(sc, &hserror, &hsparam1, &hsparam2, 3590fca6f8bSJohn Baldwin hsmsg == 0)) != 0) { 360da8bb3a3SMike Smith /* report first time around... */ 361da8bb3a3SMike Smith if (hsmsg == 0) { 362da8bb3a3SMike Smith device_printf(sc->mlx_dev, "controller initialisation in progress...\n"); 363da8bb3a3SMike Smith hsmsg = 1; 364da8bb3a3SMike Smith } 365da8bb3a3SMike Smith /* did we get a real message? */ 366da8bb3a3SMike Smith if (hscode == 2) { 367da8bb3a3SMike Smith hscode = mlx_fw_message(sc, hserror, hsparam1, hsparam2); 368da8bb3a3SMike Smith /* fatal initialisation error? */ 369da8bb3a3SMike Smith if (hscode != 0) { 370da8bb3a3SMike Smith return(ENXIO); 371da8bb3a3SMike Smith } 372da8bb3a3SMike Smith } 373da8bb3a3SMike Smith } 374da8bb3a3SMike Smith if (hsmsg == 1) 375da8bb3a3SMike Smith device_printf(sc->mlx_dev, "initialisation complete.\n"); 376da8bb3a3SMike Smith 377da8bb3a3SMike Smith /* 3781ac4b82bSMike Smith * Allocate and connect our interrupt. 3791ac4b82bSMike Smith */ 3801ac4b82bSMike Smith rid = 0; 3815f96beb9SNate Lawson sc->mlx_irq = bus_alloc_resource_any(sc->mlx_dev, SYS_RES_IRQ, &rid, 3825f96beb9SNate Lawson RF_SHAREABLE | RF_ACTIVE); 3831ac4b82bSMike Smith if (sc->mlx_irq == NULL) { 384421f2f7dSMike Smith device_printf(sc->mlx_dev, "can't allocate interrupt\n"); 3851ac4b82bSMike Smith return(ENXIO); 3861ac4b82bSMike Smith } 3870fca6f8bSJohn Baldwin error = bus_setup_intr(sc->mlx_dev, sc->mlx_irq, INTR_TYPE_BIO | 3880fca6f8bSJohn Baldwin INTR_ENTROPY | INTR_MPSAFE, NULL, mlx_intr, sc, &sc->mlx_intr); 3891ac4b82bSMike Smith if (error) { 390421f2f7dSMike Smith device_printf(sc->mlx_dev, "can't set up interrupt\n"); 3911ac4b82bSMike Smith return(ENXIO); 3921ac4b82bSMike Smith } 3931ac4b82bSMike Smith 3941ac4b82bSMike Smith /* 3951ac4b82bSMike Smith * Create DMA tag for mapping buffers into controller-addressable space. 3961ac4b82bSMike Smith */ 3971ac4b82bSMike Smith error = bus_dma_tag_create(sc->mlx_parent_dmat, /* parent */ 3981b4404f9SScott Long 1, 0, /* align, boundary */ 3991ac4b82bSMike Smith BUS_SPACE_MAXADDR, /* lowaddr */ 4001ac4b82bSMike Smith BUS_SPACE_MAXADDR, /* highaddr */ 4011ac4b82bSMike Smith NULL, NULL, /* filter, filterarg */ 4026f954fb3SAlexander Motin MLX_MAXPHYS, /* maxsize */ 4036f954fb3SAlexander Motin MLX_NSEG, /* nsegments */ 4041ac4b82bSMike Smith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 4051ac4b82bSMike Smith 0, /* flags */ 406f6b1c44dSScott Long busdma_lock_mutex, /* lockfunc */ 4070fca6f8bSJohn Baldwin &sc->mlx_io_lock, /* lockarg */ 4081ac4b82bSMike Smith &sc->mlx_buffer_dmat); 4091ac4b82bSMike Smith if (error != 0) { 4101ac4b82bSMike Smith device_printf(sc->mlx_dev, "can't allocate buffer DMA tag\n"); 4111ac4b82bSMike Smith return(ENOMEM); 4121ac4b82bSMike Smith } 4131ac4b82bSMike Smith 4141ac4b82bSMike Smith /* 4151b4404f9SScott Long * Create some initial scatter/gather mappings so we can run the probe 4161b4404f9SScott Long * commands. 4171ac4b82bSMike Smith */ 4181ac4b82bSMike Smith error = mlx_sglist_map(sc); 4191ac4b82bSMike Smith if (error != 0) { 420421f2f7dSMike Smith device_printf(sc->mlx_dev, "can't make initial s/g list mapping\n"); 4211ac4b82bSMike Smith return(error); 4221ac4b82bSMike Smith } 4231ac4b82bSMike Smith 424baff09dbSMike Smith /* 425baff09dbSMike Smith * We don't (yet) know where the event log is up to. 426baff09dbSMike Smith */ 427baff09dbSMike Smith sc->mlx_currevent = -1; 428baff09dbSMike Smith 429baff09dbSMike Smith /* 430baff09dbSMike Smith * Obtain controller feature information 431baff09dbSMike Smith */ 4320fca6f8bSJohn Baldwin MLX_IO_LOCK(sc); 4339eee27f1SMike Smith if ((sc->mlx_enq2 = mlx_enquire(sc, MLX_CMD_ENQUIRY2, sizeof(struct mlx_enquiry2), NULL)) == NULL) { 4340fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc); 4351ac4b82bSMike Smith device_printf(sc->mlx_dev, "ENQUIRY2 failed\n"); 4361ac4b82bSMike Smith return(ENXIO); 4371ac4b82bSMike Smith } 4381ac4b82bSMike Smith 4399eee27f1SMike Smith /* 4401ac4b82bSMike Smith * Do quirk/feature related things. 4411ac4b82bSMike Smith */ 4429eee27f1SMike Smith fwminor = (sc->mlx_enq2->me_firmware_id >> 8) & 0xff; 4431ac4b82bSMike Smith switch(sc->mlx_iftype) { 444da8bb3a3SMike Smith case MLX_IFTYPE_2: 445da8bb3a3SMike Smith /* These controllers don't report the firmware version in the ENQUIRY2 response */ 446da8bb3a3SMike Smith if ((meo = mlx_enquire(sc, MLX_CMD_ENQUIRY_OLD, sizeof(struct mlx_enquiry_old), NULL)) == NULL) { 4470fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc); 448da8bb3a3SMike Smith device_printf(sc->mlx_dev, "ENQUIRY_OLD failed\n"); 449da8bb3a3SMike Smith return(ENXIO); 450da8bb3a3SMike Smith } 451da8bb3a3SMike Smith sc->mlx_enq2->me_firmware_id = ('0' << 24) | (0 << 16) | (meo->me_fwminor << 8) | meo->me_fwmajor; 452da8bb3a3SMike Smith 453da8bb3a3SMike Smith /* XXX require 2.42 or better (PCI) or 2.14 or better (EISA) */ 454da8bb3a3SMike Smith if (meo->me_fwminor < 42) { 455da8bb3a3SMike Smith device_printf(sc->mlx_dev, " *** WARNING *** This firmware revision is not recommended\n"); 456da8bb3a3SMike Smith device_printf(sc->mlx_dev, " *** WARNING *** Use revision 2.42 or later\n"); 457da8bb3a3SMike Smith } 458caa32ef5SColin Percival free(meo, M_DEVBUF); 459da8bb3a3SMike Smith break; 4601ac4b82bSMike Smith case MLX_IFTYPE_3: 461f6b84b08SMike Smith /* XXX certify 3.52? */ 4629eee27f1SMike Smith if (fwminor < 51) { 4634b006d7bSMike Smith device_printf(sc->mlx_dev, " *** WARNING *** This firmware revision is not recommended\n"); 4644b006d7bSMike Smith device_printf(sc->mlx_dev, " *** WARNING *** Use revision 3.51 or later\n"); 4651ac4b82bSMike Smith } 4661ac4b82bSMike Smith break; 467f6b84b08SMike Smith case MLX_IFTYPE_4: 468f6b84b08SMike Smith /* XXX certify firmware versions? */ 4699eee27f1SMike Smith if (fwminor < 6) { 4704b006d7bSMike Smith device_printf(sc->mlx_dev, " *** WARNING *** This firmware revision is not recommended\n"); 4714b006d7bSMike Smith device_printf(sc->mlx_dev, " *** WARNING *** Use revision 4.06 or later\n"); 472f6b84b08SMike Smith } 473f6b84b08SMike Smith break; 4745792b7feSMike Smith case MLX_IFTYPE_5: 4759eee27f1SMike Smith if (fwminor < 7) { 4765792b7feSMike Smith device_printf(sc->mlx_dev, " *** WARNING *** This firmware revision is not recommended\n"); 4775792b7feSMike Smith device_printf(sc->mlx_dev, " *** WARNING *** Use revision 5.07 or later\n"); 4785792b7feSMike Smith } 4795792b7feSMike Smith break; 4801ac4b82bSMike Smith default: 4810fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc); 4821ac4b82bSMike Smith return(ENXIO); /* should never happen */ 4831ac4b82bSMike Smith } 4840fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc); 4851ac4b82bSMike Smith 4861ac4b82bSMike Smith /* 487baff09dbSMike Smith * Create the final scatter/gather mappings now that we have characterised the controller. 4881ac4b82bSMike Smith */ 4891ac4b82bSMike Smith error = mlx_sglist_map(sc); 4901ac4b82bSMike Smith if (error != 0) { 491baff09dbSMike Smith device_printf(sc->mlx_dev, "can't make final s/g list mapping\n"); 4921ac4b82bSMike Smith return(error); 4931ac4b82bSMike Smith } 4941ac4b82bSMike Smith 4951ac4b82bSMike Smith /* 496421f2f7dSMike Smith * No user-requested background operation is in progress. 4971ac4b82bSMike Smith */ 498421f2f7dSMike Smith sc->mlx_background = 0; 499421f2f7dSMike Smith sc->mlx_rebuildstat.rs_code = MLX_REBUILDSTAT_IDLE; 5001ac4b82bSMike Smith 5011ac4b82bSMike Smith /* 502da8bb3a3SMike Smith * Create the control device. 5031ac4b82bSMike Smith */ 504e78a5a3fSEd Schouten sc->mlx_dev_t = make_dev(&mlx_cdevsw, 0, UID_ROOT, GID_OPERATOR, 505da8bb3a3SMike Smith S_IRUSR | S_IWUSR, "mlx%d", device_get_unit(sc->mlx_dev)); 506e78a5a3fSEd Schouten sc->mlx_dev_t->si_drv1 = sc; 5071ac4b82bSMike Smith 5081ac4b82bSMike Smith /* 5091ac4b82bSMike Smith * Start the timeout routine. 5101ac4b82bSMike Smith */ 5110fca6f8bSJohn Baldwin callout_reset(&sc->mlx_timeout, hz, mlx_periodic, sc); 5121ac4b82bSMike Smith 513da8bb3a3SMike Smith /* print a little information about the controller */ 514da8bb3a3SMike Smith mlx_describe_controller(sc); 515da8bb3a3SMike Smith 5161ac4b82bSMike Smith return(0); 5171ac4b82bSMike Smith } 5181ac4b82bSMike Smith 5191ac4b82bSMike Smith /******************************************************************************** 5201ac4b82bSMike Smith * Locate disk resources and attach children to them. 5211ac4b82bSMike Smith */ 5221ac4b82bSMike Smith void 5231ac4b82bSMike Smith mlx_startup(struct mlx_softc *sc) 5241ac4b82bSMike Smith { 5251ac4b82bSMike Smith struct mlx_enq_sys_drive *mes; 5261ac4b82bSMike Smith struct mlx_sysdrive *dr; 5271ac4b82bSMike Smith int i, error; 5281ac4b82bSMike Smith 529da8bb3a3SMike Smith debug_called(1); 5301ac4b82bSMike Smith 5311ac4b82bSMike Smith /* 5321ac4b82bSMike Smith * Scan all the system drives and attach children for those that 5331ac4b82bSMike Smith * don't currently have them. 5341ac4b82bSMike Smith */ 5350fca6f8bSJohn Baldwin MLX_IO_LOCK(sc); 5361ac4b82bSMike Smith mes = mlx_enquire(sc, MLX_CMD_ENQSYSDRIVE, sizeof(*mes) * MLX_MAXDRIVES, NULL); 5370fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc); 5381ac4b82bSMike Smith if (mes == NULL) { 5399eee27f1SMike Smith device_printf(sc->mlx_dev, "error fetching drive status\n"); 5401ac4b82bSMike Smith return; 5411ac4b82bSMike Smith } 5421ac4b82bSMike Smith 5431ac4b82bSMike Smith /* iterate over drives returned */ 5440fca6f8bSJohn Baldwin MLX_CONFIG_LOCK(sc); 5451ac4b82bSMike Smith for (i = 0, dr = &sc->mlx_sysdrive[0]; 5461ac4b82bSMike Smith (i < MLX_MAXDRIVES) && (mes[i].sd_size != 0xffffffff); 5471ac4b82bSMike Smith i++, dr++) { 5481ac4b82bSMike Smith /* are we already attached to this drive? */ 5491ac4b82bSMike Smith if (dr->ms_disk == 0) { 5501ac4b82bSMike Smith /* pick up drive information */ 5511ac4b82bSMike Smith dr->ms_size = mes[i].sd_size; 552f6b84b08SMike Smith dr->ms_raidlevel = mes[i].sd_raidlevel & 0xf; 5531ac4b82bSMike Smith dr->ms_state = mes[i].sd_state; 5541ac4b82bSMike Smith 5551ac4b82bSMike Smith /* generate geometry information */ 5561ac4b82bSMike Smith if (sc->mlx_geom == MLX_GEOM_128_32) { 5571ac4b82bSMike Smith dr->ms_heads = 128; 5581ac4b82bSMike Smith dr->ms_sectors = 32; 5591ac4b82bSMike Smith dr->ms_cylinders = dr->ms_size / (128 * 32); 5601ac4b82bSMike Smith } else { /* MLX_GEOM_255/63 */ 5611ac4b82bSMike Smith dr->ms_heads = 255; 5621ac4b82bSMike Smith dr->ms_sectors = 63; 5631ac4b82bSMike Smith dr->ms_cylinders = dr->ms_size / (255 * 63); 5641ac4b82bSMike Smith } 565fe0d4089SMatthew N. Dodd dr->ms_disk = device_add_child(sc->mlx_dev, /*"mlxd"*/NULL, -1); 5661ac4b82bSMike Smith if (dr->ms_disk == 0) 5671ac4b82bSMike Smith device_printf(sc->mlx_dev, "device_add_child failed\n"); 568fe0d4089SMatthew N. Dodd device_set_ivars(dr->ms_disk, dr); 5691ac4b82bSMike Smith } 5701ac4b82bSMike Smith } 5711ac4b82bSMike Smith free(mes, M_DEVBUF); 5721ac4b82bSMike Smith if ((error = bus_generic_attach(sc->mlx_dev)) != 0) 5731ac4b82bSMike Smith device_printf(sc->mlx_dev, "bus_generic_attach returned %d", error); 5741ac4b82bSMike Smith 5751ac4b82bSMike Smith /* mark controller back up */ 5760fca6f8bSJohn Baldwin MLX_IO_LOCK(sc); 5771ac4b82bSMike Smith sc->mlx_state &= ~MLX_STATE_SHUTDOWN; 5781ac4b82bSMike Smith 5791ac4b82bSMike Smith /* enable interrupts */ 5801ac4b82bSMike Smith sc->mlx_intaction(sc, MLX_INTACTION_ENABLE); 5810fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc); 5820fca6f8bSJohn Baldwin MLX_CONFIG_UNLOCK(sc); 5831ac4b82bSMike Smith } 5841ac4b82bSMike Smith 5851ac4b82bSMike Smith /******************************************************************************** 5861ac4b82bSMike Smith * Disconnect from the controller completely, in preparation for unload. 5871ac4b82bSMike Smith */ 5881ac4b82bSMike Smith int 5891ac4b82bSMike Smith mlx_detach(device_t dev) 5901ac4b82bSMike Smith { 5911ac4b82bSMike Smith struct mlx_softc *sc = device_get_softc(dev); 5925792b7feSMike Smith struct mlxd_softc *mlxd; 5930fca6f8bSJohn Baldwin int i, error; 5941ac4b82bSMike Smith 595da8bb3a3SMike Smith debug_called(1); 5961ac4b82bSMike Smith 5975792b7feSMike Smith error = EBUSY; 5980fca6f8bSJohn Baldwin MLX_CONFIG_LOCK(sc); 5991ac4b82bSMike Smith if (sc->mlx_state & MLX_STATE_OPEN) 6005792b7feSMike Smith goto out; 6011ac4b82bSMike Smith 6025792b7feSMike Smith for (i = 0; i < MLX_MAXDRIVES; i++) { 6035792b7feSMike Smith if (sc->mlx_sysdrive[i].ms_disk != 0) { 6045792b7feSMike Smith mlxd = device_get_softc(sc->mlx_sysdrive[i].ms_disk); 6055792b7feSMike Smith if (mlxd->mlxd_flags & MLXD_OPEN) { /* drive is mounted, abort detach */ 6065792b7feSMike Smith device_printf(sc->mlx_sysdrive[i].ms_disk, "still open, can't detach\n"); 6075792b7feSMike Smith goto out; 6085792b7feSMike Smith } 6095792b7feSMike Smith } 6105792b7feSMike Smith } 6111ac4b82bSMike Smith if ((error = mlx_shutdown(dev))) 6125792b7feSMike Smith goto out; 6130fca6f8bSJohn Baldwin MLX_CONFIG_UNLOCK(sc); 6141ac4b82bSMike Smith 6151ac4b82bSMike Smith mlx_free(sc); 6161ac4b82bSMike Smith 6170fca6f8bSJohn Baldwin return (0); 6185792b7feSMike Smith out: 6190fca6f8bSJohn Baldwin MLX_CONFIG_UNLOCK(sc); 6205792b7feSMike Smith return(error); 6211ac4b82bSMike Smith } 6221ac4b82bSMike Smith 6231ac4b82bSMike Smith /******************************************************************************** 6241ac4b82bSMike Smith * Bring the controller down to a dormant state and detach all child devices. 6251ac4b82bSMike Smith * 6261ac4b82bSMike Smith * This function is called before detach, system shutdown, or before performing 6271ac4b82bSMike Smith * an operation which may add or delete system disks. (Call mlx_startup to 6281ac4b82bSMike Smith * resume normal operation.) 6291ac4b82bSMike Smith * 6308177437dSPoul-Henning Kamp * Note that we can assume that the bioq on the controller is empty, as we won't 6311ac4b82bSMike Smith * allow shutdown if any device is open. 6321ac4b82bSMike Smith */ 6331ac4b82bSMike Smith int 6341ac4b82bSMike Smith mlx_shutdown(device_t dev) 6351ac4b82bSMike Smith { 6361ac4b82bSMike Smith struct mlx_softc *sc = device_get_softc(dev); 6370fca6f8bSJohn Baldwin int error; 6380fca6f8bSJohn Baldwin 6390fca6f8bSJohn Baldwin MLX_CONFIG_LOCK(sc); 6400fca6f8bSJohn Baldwin error = mlx_shutdown_locked(sc); 6410fca6f8bSJohn Baldwin MLX_CONFIG_UNLOCK(sc); 6420fca6f8bSJohn Baldwin return (error); 6430fca6f8bSJohn Baldwin } 6440fca6f8bSJohn Baldwin 6450fca6f8bSJohn Baldwin static int 6460fca6f8bSJohn Baldwin mlx_shutdown_locked(struct mlx_softc *sc) 6470fca6f8bSJohn Baldwin { 6480fca6f8bSJohn Baldwin int i, error; 6491ac4b82bSMike Smith 650da8bb3a3SMike Smith debug_called(1); 6511ac4b82bSMike Smith 6520fca6f8bSJohn Baldwin MLX_CONFIG_ASSERT_LOCKED(sc); 6531ac4b82bSMike Smith 6540fca6f8bSJohn Baldwin MLX_IO_LOCK(sc); 6551ac4b82bSMike Smith sc->mlx_state |= MLX_STATE_SHUTDOWN; 6565792b7feSMike Smith sc->mlx_intaction(sc, MLX_INTACTION_DISABLE); 6571ac4b82bSMike Smith 6581ac4b82bSMike Smith /* flush controller */ 6591ac4b82bSMike Smith device_printf(sc->mlx_dev, "flushing cache..."); 6601ac4b82bSMike Smith if (mlx_flush(sc)) { 6611ac4b82bSMike Smith printf("failed\n"); 6621ac4b82bSMike Smith } else { 6631ac4b82bSMike Smith printf("done\n"); 6641ac4b82bSMike Smith } 6650fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc); 6661ac4b82bSMike Smith 6671ac4b82bSMike Smith /* delete all our child devices */ 6681ac4b82bSMike Smith for (i = 0; i < MLX_MAXDRIVES; i++) { 6691ac4b82bSMike Smith if (sc->mlx_sysdrive[i].ms_disk != 0) { 6701ac4b82bSMike Smith if ((error = device_delete_child(sc->mlx_dev, sc->mlx_sysdrive[i].ms_disk)) != 0) 6710fca6f8bSJohn Baldwin return (error); 6721ac4b82bSMike Smith sc->mlx_sysdrive[i].ms_disk = 0; 6731ac4b82bSMike Smith } 6741ac4b82bSMike Smith } 6751ac4b82bSMike Smith 6760fca6f8bSJohn Baldwin return (0); 6771ac4b82bSMike Smith } 6781ac4b82bSMike Smith 6791ac4b82bSMike Smith /******************************************************************************** 6801ac4b82bSMike Smith * Bring the controller to a quiescent state, ready for system suspend. 6811ac4b82bSMike Smith */ 6821ac4b82bSMike Smith int 6831ac4b82bSMike Smith mlx_suspend(device_t dev) 6841ac4b82bSMike Smith { 6851ac4b82bSMike Smith struct mlx_softc *sc = device_get_softc(dev); 6861ac4b82bSMike Smith 687da8bb3a3SMike Smith debug_called(1); 6881ac4b82bSMike Smith 6890fca6f8bSJohn Baldwin MLX_IO_LOCK(sc); 6901ac4b82bSMike Smith sc->mlx_state |= MLX_STATE_SUSPEND; 6911ac4b82bSMike Smith 6921ac4b82bSMike Smith /* flush controller */ 6931ac4b82bSMike Smith device_printf(sc->mlx_dev, "flushing cache..."); 6941ac4b82bSMike Smith printf("%s\n", mlx_flush(sc) ? "failed" : "done"); 6951ac4b82bSMike Smith 6961ac4b82bSMike Smith sc->mlx_intaction(sc, MLX_INTACTION_DISABLE); 6970fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc); 6981ac4b82bSMike Smith 6991ac4b82bSMike Smith return(0); 7001ac4b82bSMike Smith } 7011ac4b82bSMike Smith 7021ac4b82bSMike Smith /******************************************************************************** 7031ac4b82bSMike Smith * Bring the controller back to a state ready for operation. 7041ac4b82bSMike Smith */ 7051ac4b82bSMike Smith int 7061ac4b82bSMike Smith mlx_resume(device_t dev) 7071ac4b82bSMike Smith { 7081ac4b82bSMike Smith struct mlx_softc *sc = device_get_softc(dev); 7091ac4b82bSMike Smith 710da8bb3a3SMike Smith debug_called(1); 7111ac4b82bSMike Smith 7120fca6f8bSJohn Baldwin MLX_IO_LOCK(sc); 7131ac4b82bSMike Smith sc->mlx_state &= ~MLX_STATE_SUSPEND; 7141ac4b82bSMike Smith sc->mlx_intaction(sc, MLX_INTACTION_ENABLE); 7150fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc); 7161ac4b82bSMike Smith 7171ac4b82bSMike Smith return(0); 7181ac4b82bSMike Smith } 7191ac4b82bSMike Smith 7201ac4b82bSMike Smith /******************************************************************************* 7211ac4b82bSMike Smith * Take an interrupt, or be poked by other code to look for interrupt-worthy 7221ac4b82bSMike Smith * status. 7231ac4b82bSMike Smith */ 7241ac4b82bSMike Smith void 7251ac4b82bSMike Smith mlx_intr(void *arg) 7261ac4b82bSMike Smith { 7271ac4b82bSMike Smith struct mlx_softc *sc = (struct mlx_softc *)arg; 7281ac4b82bSMike Smith 729da8bb3a3SMike Smith debug_called(1); 7301ac4b82bSMike Smith 7315792b7feSMike Smith /* collect finished commands, queue anything waiting */ 7320fca6f8bSJohn Baldwin MLX_IO_LOCK(sc); 7330fca6f8bSJohn Baldwin mlx_done(sc, 1); 7340fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc); 7351ac4b82bSMike Smith }; 7361ac4b82bSMike Smith 7371ac4b82bSMike Smith /******************************************************************************* 7381ac4b82bSMike Smith * Receive a buf structure from a child device and queue it on a particular 7391ac4b82bSMike Smith * disk resource, then poke the disk resource to start as much work as it can. 7401ac4b82bSMike Smith */ 7411ac4b82bSMike Smith int 742b04e4c12SJohn Baldwin mlx_submit_buf(struct mlx_softc *sc, struct bio *bp) 7431ac4b82bSMike Smith { 7444b006d7bSMike Smith 745da8bb3a3SMike Smith debug_called(1); 7461ac4b82bSMike Smith 7470fca6f8bSJohn Baldwin MLX_IO_ASSERT_LOCKED(sc); 748b04e4c12SJohn Baldwin bioq_insert_tail(&sc->mlx_bioq, bp); 7491ac4b82bSMike Smith sc->mlx_waitbufs++; 7501ac4b82bSMike Smith mlx_startio(sc); 7511ac4b82bSMike Smith return(0); 7521ac4b82bSMike Smith } 7531ac4b82bSMike Smith 7541ac4b82bSMike Smith /******************************************************************************** 7551ac4b82bSMike Smith * Accept an open operation on the control device. 7561ac4b82bSMike Smith */ 7571ac4b82bSMike Smith int 75889c9c53dSPoul-Henning Kamp mlx_open(struct cdev *dev, int flags, int fmt, struct thread *td) 7591ac4b82bSMike Smith { 760e78a5a3fSEd Schouten struct mlx_softc *sc = dev->si_drv1; 7611ac4b82bSMike Smith 7620fca6f8bSJohn Baldwin MLX_CONFIG_LOCK(sc); 7630fca6f8bSJohn Baldwin MLX_IO_LOCK(sc); 7641ac4b82bSMike Smith sc->mlx_state |= MLX_STATE_OPEN; 7650fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc); 7660fca6f8bSJohn Baldwin MLX_CONFIG_UNLOCK(sc); 7671ac4b82bSMike Smith return(0); 7681ac4b82bSMike Smith } 7691ac4b82bSMike Smith 7701ac4b82bSMike Smith /******************************************************************************** 7711ac4b82bSMike Smith * Accept the last close on the control device. 7721ac4b82bSMike Smith */ 7731ac4b82bSMike Smith int 77489c9c53dSPoul-Henning Kamp mlx_close(struct cdev *dev, int flags, int fmt, struct thread *td) 7751ac4b82bSMike Smith { 776e78a5a3fSEd Schouten struct mlx_softc *sc = dev->si_drv1; 7771ac4b82bSMike Smith 7780fca6f8bSJohn Baldwin MLX_CONFIG_LOCK(sc); 7790fca6f8bSJohn Baldwin MLX_IO_LOCK(sc); 7801ac4b82bSMike Smith sc->mlx_state &= ~MLX_STATE_OPEN; 7810fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc); 7820fca6f8bSJohn Baldwin MLX_CONFIG_UNLOCK(sc); 7831ac4b82bSMike Smith return (0); 7841ac4b82bSMike Smith } 7851ac4b82bSMike Smith 7861ac4b82bSMike Smith /******************************************************************************** 7871ac4b82bSMike Smith * Handle controller-specific control operations. 7881ac4b82bSMike Smith */ 7891ac4b82bSMike Smith int 79089c9c53dSPoul-Henning Kamp mlx_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, struct thread *td) 7911ac4b82bSMike Smith { 792e78a5a3fSEd Schouten struct mlx_softc *sc = dev->si_drv1; 793421f2f7dSMike Smith struct mlx_rebuild_request *rb = (struct mlx_rebuild_request *)addr; 794421f2f7dSMike Smith struct mlx_rebuild_status *rs = (struct mlx_rebuild_status *)addr; 7951ac4b82bSMike Smith int *arg = (int *)addr; 7961ac4b82bSMike Smith struct mlx_pause *mp; 7971ac4b82bSMike Smith struct mlx_sysdrive *dr; 7981ac4b82bSMike Smith struct mlxd_softc *mlxd; 7991ac4b82bSMike Smith int i, error; 8001ac4b82bSMike Smith 8011ac4b82bSMike Smith switch(cmd) { 8021ac4b82bSMike Smith /* 8031ac4b82bSMike Smith * Enumerate connected system drives; returns the first system drive's 8041ac4b82bSMike Smith * unit number if *arg is -1, or the next unit after *arg if it's 8051ac4b82bSMike Smith * a valid unit on this controller. 8061ac4b82bSMike Smith */ 8071ac4b82bSMike Smith case MLX_NEXT_CHILD: 8081ac4b82bSMike Smith /* search system drives */ 8090fca6f8bSJohn Baldwin MLX_CONFIG_LOCK(sc); 8101ac4b82bSMike Smith for (i = 0; i < MLX_MAXDRIVES; i++) { 8111ac4b82bSMike Smith /* is this one attached? */ 8121ac4b82bSMike Smith if (sc->mlx_sysdrive[i].ms_disk != 0) { 8131ac4b82bSMike Smith /* looking for the next one we come across? */ 8141ac4b82bSMike Smith if (*arg == -1) { 81529e6fa3aSStephane E. Potvin *arg = device_get_unit(sc->mlx_sysdrive[i].ms_disk); 8160fca6f8bSJohn Baldwin MLX_CONFIG_UNLOCK(sc); 8171ac4b82bSMike Smith return(0); 8181ac4b82bSMike Smith } 8191ac4b82bSMike Smith /* we want the one after this one */ 8201ac4b82bSMike Smith if (*arg == device_get_unit(sc->mlx_sysdrive[i].ms_disk)) 8211ac4b82bSMike Smith *arg = -1; 8221ac4b82bSMike Smith } 8231ac4b82bSMike Smith } 8240fca6f8bSJohn Baldwin MLX_CONFIG_UNLOCK(sc); 8251ac4b82bSMike Smith return(ENOENT); 8261ac4b82bSMike Smith 8271ac4b82bSMike Smith /* 8281ac4b82bSMike Smith * Scan the controller to see whether new drives have appeared. 8291ac4b82bSMike Smith */ 8301ac4b82bSMike Smith case MLX_RESCAN_DRIVES: 8310fca6f8bSJohn Baldwin mtx_lock(&Giant); 8321ac4b82bSMike Smith mlx_startup(sc); 8330fca6f8bSJohn Baldwin mtx_unlock(&Giant); 8341ac4b82bSMike Smith return(0); 8351ac4b82bSMike Smith 8361ac4b82bSMike Smith /* 8371ac4b82bSMike Smith * Disconnect from the specified drive; it may be about to go 8381ac4b82bSMike Smith * away. 8391ac4b82bSMike Smith */ 8401ac4b82bSMike Smith case MLX_DETACH_DRIVE: /* detach one drive */ 8410fca6f8bSJohn Baldwin MLX_CONFIG_LOCK(sc); 8421ac4b82bSMike Smith if (((dr = mlx_findunit(sc, *arg)) == NULL) || 8430fca6f8bSJohn Baldwin ((mlxd = device_get_softc(dr->ms_disk)) == NULL)) { 8440fca6f8bSJohn Baldwin MLX_CONFIG_UNLOCK(sc); 8451ac4b82bSMike Smith return(ENOENT); 8460fca6f8bSJohn Baldwin } 8471ac4b82bSMike Smith 8481ac4b82bSMike Smith device_printf(dr->ms_disk, "detaching..."); 8491ac4b82bSMike Smith error = 0; 8501ac4b82bSMike Smith if (mlxd->mlxd_flags & MLXD_OPEN) { 8511ac4b82bSMike Smith error = EBUSY; 8521ac4b82bSMike Smith goto detach_out; 8531ac4b82bSMike Smith } 8541ac4b82bSMike Smith 8551ac4b82bSMike Smith /* flush controller */ 8560fca6f8bSJohn Baldwin MLX_IO_LOCK(sc); 8571ac4b82bSMike Smith if (mlx_flush(sc)) { 8580fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc); 8591ac4b82bSMike Smith error = EBUSY; 8601ac4b82bSMike Smith goto detach_out; 8611ac4b82bSMike Smith } 8620fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc); 8631ac4b82bSMike Smith 8641ac4b82bSMike Smith /* nuke drive */ 8651ac4b82bSMike Smith if ((error = device_delete_child(sc->mlx_dev, dr->ms_disk)) != 0) 8661ac4b82bSMike Smith goto detach_out; 8671ac4b82bSMike Smith dr->ms_disk = 0; 8681ac4b82bSMike Smith 8691ac4b82bSMike Smith detach_out: 8700fca6f8bSJohn Baldwin MLX_CONFIG_UNLOCK(sc); 8711ac4b82bSMike Smith if (error) { 8721ac4b82bSMike Smith printf("failed\n"); 8731ac4b82bSMike Smith } else { 8741ac4b82bSMike Smith printf("done\n"); 8751ac4b82bSMike Smith } 8761ac4b82bSMike Smith return(error); 8771ac4b82bSMike Smith 8781ac4b82bSMike Smith /* 8791ac4b82bSMike Smith * Pause one or more SCSI channels for a period of time, to assist 8801ac4b82bSMike Smith * in the process of hot-swapping devices. 8811ac4b82bSMike Smith * 8821ac4b82bSMike Smith * Note that at least the 3.51 firmware on the DAC960PL doesn't seem 8831ac4b82bSMike Smith * to do this right. 8841ac4b82bSMike Smith */ 8851ac4b82bSMike Smith case MLX_PAUSE_CHANNEL: /* schedule a channel pause */ 8861ac4b82bSMike Smith /* Does this command work on this firmware? */ 8871ac4b82bSMike Smith if (!(sc->mlx_feature & MLX_FEAT_PAUSEWORKS)) 8881ac4b82bSMike Smith return(EOPNOTSUPP); 8891ac4b82bSMike Smith 8900fca6f8bSJohn Baldwin /* check time values */ 8911ac4b82bSMike Smith mp = (struct mlx_pause *)addr; 8920fca6f8bSJohn Baldwin if ((mp->mp_when < 0) || (mp->mp_when > 3600)) 8930fca6f8bSJohn Baldwin return(EINVAL); 8940fca6f8bSJohn Baldwin if ((mp->mp_howlong < 1) || (mp->mp_howlong > (0xf * 30))) 8950fca6f8bSJohn Baldwin return(EINVAL); 8960fca6f8bSJohn Baldwin 8970fca6f8bSJohn Baldwin MLX_IO_LOCK(sc); 8981ac4b82bSMike Smith if ((mp->mp_which == MLX_PAUSE_CANCEL) && (sc->mlx_pause.mp_when != 0)) { 8991ac4b82bSMike Smith /* cancel a pending pause operation */ 9001ac4b82bSMike Smith sc->mlx_pause.mp_which = 0; 9011ac4b82bSMike Smith } else { 9021ac4b82bSMike Smith /* fix for legal channels */ 9039eee27f1SMike Smith mp->mp_which &= ((1 << sc->mlx_enq2->me_actual_channels) -1); 9041ac4b82bSMike Smith 9051ac4b82bSMike Smith /* check for a pause currently running */ 9060fca6f8bSJohn Baldwin if ((sc->mlx_pause.mp_which != 0) && (sc->mlx_pause.mp_when == 0)) { 9070fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc); 9081ac4b82bSMike Smith return(EBUSY); 9090fca6f8bSJohn Baldwin } 9101ac4b82bSMike Smith 9111ac4b82bSMike Smith /* looks ok, go with it */ 9121ac4b82bSMike Smith sc->mlx_pause.mp_which = mp->mp_which; 9131ac4b82bSMike Smith sc->mlx_pause.mp_when = time_second + mp->mp_when; 9141ac4b82bSMike Smith sc->mlx_pause.mp_howlong = sc->mlx_pause.mp_when + mp->mp_howlong; 9151ac4b82bSMike Smith } 9160fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc); 9171ac4b82bSMike Smith return(0); 9181ac4b82bSMike Smith 9191ac4b82bSMike Smith /* 9201ac4b82bSMike Smith * Accept a command passthrough-style. 9211ac4b82bSMike Smith */ 9221ac4b82bSMike Smith case MLX_COMMAND: 9231ac4b82bSMike Smith return(mlx_user_command(sc, (struct mlx_usercommand *)addr)); 9241ac4b82bSMike Smith 925421f2f7dSMike Smith /* 926421f2f7dSMike Smith * Start a rebuild on a given SCSI disk 927421f2f7dSMike Smith */ 928421f2f7dSMike Smith case MLX_REBUILDASYNC: 9290fca6f8bSJohn Baldwin MLX_IO_LOCK(sc); 930421f2f7dSMike Smith if (sc->mlx_background != 0) { 9310fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc); 932421f2f7dSMike Smith rb->rr_status = 0x0106; 933421f2f7dSMike Smith return(EBUSY); 934421f2f7dSMike Smith } 935421f2f7dSMike Smith rb->rr_status = mlx_rebuild(sc, rb->rr_channel, rb->rr_target); 936421f2f7dSMike Smith switch (rb->rr_status) { 937421f2f7dSMike Smith case 0: 938421f2f7dSMike Smith error = 0; 939421f2f7dSMike Smith break; 940421f2f7dSMike Smith case 0x10000: 941421f2f7dSMike Smith error = ENOMEM; /* couldn't set up the command */ 942421f2f7dSMike Smith break; 943421f2f7dSMike Smith case 0x0002: 944421f2f7dSMike Smith error = EBUSY; 945421f2f7dSMike Smith break; 946421f2f7dSMike Smith case 0x0104: 947421f2f7dSMike Smith error = EIO; 948421f2f7dSMike Smith break; 949421f2f7dSMike Smith case 0x0105: 950421f2f7dSMike Smith error = ERANGE; 951421f2f7dSMike Smith break; 952421f2f7dSMike Smith case 0x0106: 953421f2f7dSMike Smith error = EBUSY; 954421f2f7dSMike Smith break; 955421f2f7dSMike Smith default: 956421f2f7dSMike Smith error = EINVAL; 957421f2f7dSMike Smith break; 958421f2f7dSMike Smith } 959421f2f7dSMike Smith if (error == 0) 960421f2f7dSMike Smith sc->mlx_background = MLX_BACKGROUND_REBUILD; 9610fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc); 962421f2f7dSMike Smith return(error); 963421f2f7dSMike Smith 964421f2f7dSMike Smith /* 965421f2f7dSMike Smith * Get the status of the current rebuild or consistency check. 966421f2f7dSMike Smith */ 967421f2f7dSMike Smith case MLX_REBUILDSTAT: 9680fca6f8bSJohn Baldwin MLX_IO_LOCK(sc); 969421f2f7dSMike Smith *rs = sc->mlx_rebuildstat; 9700fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc); 971421f2f7dSMike Smith return(0); 972421f2f7dSMike Smith 973421f2f7dSMike Smith /* 974421f2f7dSMike Smith * Return the per-controller system drive number matching the 975421f2f7dSMike Smith * disk device number in (arg), if it happens to belong to us. 976421f2f7dSMike Smith */ 977421f2f7dSMike Smith case MLX_GET_SYSDRIVE: 978421f2f7dSMike Smith error = ENOENT; 9790fca6f8bSJohn Baldwin MLX_CONFIG_LOCK(sc); 9800fca6f8bSJohn Baldwin mtx_lock(&Giant); 981421f2f7dSMike Smith mlxd = (struct mlxd_softc *)devclass_get_softc(mlxd_devclass, *arg); 9820fca6f8bSJohn Baldwin mtx_unlock(&Giant); 983421f2f7dSMike Smith if ((mlxd != NULL) && (mlxd->mlxd_drive >= sc->mlx_sysdrive) && 984421f2f7dSMike Smith (mlxd->mlxd_drive < (sc->mlx_sysdrive + MLX_MAXDRIVES))) { 985421f2f7dSMike Smith error = 0; 986421f2f7dSMike Smith *arg = mlxd->mlxd_drive - sc->mlx_sysdrive; 987421f2f7dSMike Smith } 9880fca6f8bSJohn Baldwin MLX_CONFIG_UNLOCK(sc); 989421f2f7dSMike Smith return(error); 990421f2f7dSMike Smith 9911ac4b82bSMike Smith default: 9921ac4b82bSMike Smith return(ENOTTY); 9931ac4b82bSMike Smith } 9941ac4b82bSMike Smith } 9951ac4b82bSMike Smith 9961ac4b82bSMike Smith /******************************************************************************** 9971ac4b82bSMike Smith * Handle operations requested by a System Drive connected to this controller. 9981ac4b82bSMike Smith */ 9991ac4b82bSMike Smith int 10001ac4b82bSMike Smith mlx_submit_ioctl(struct mlx_softc *sc, struct mlx_sysdrive *drive, u_long cmd, 1001b40ce416SJulian Elischer caddr_t addr, int32_t flag, struct thread *td) 10021ac4b82bSMike Smith { 10031ac4b82bSMike Smith int *arg = (int *)addr; 1004421f2f7dSMike Smith int error, result; 10051ac4b82bSMike Smith 10061ac4b82bSMike Smith switch(cmd) { 10071ac4b82bSMike Smith /* 10081ac4b82bSMike Smith * Return the current status of this drive. 10091ac4b82bSMike Smith */ 10101ac4b82bSMike Smith case MLXD_STATUS: 10110fca6f8bSJohn Baldwin MLX_IO_LOCK(sc); 10121ac4b82bSMike Smith *arg = drive->ms_state; 10130fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc); 10141ac4b82bSMike Smith return(0); 10151ac4b82bSMike Smith 10161ac4b82bSMike Smith /* 1017421f2f7dSMike Smith * Start a background consistency check on this drive. 10181ac4b82bSMike Smith */ 1019421f2f7dSMike Smith case MLXD_CHECKASYNC: /* start a background consistency check */ 10200fca6f8bSJohn Baldwin MLX_IO_LOCK(sc); 1021421f2f7dSMike Smith if (sc->mlx_background != 0) { 10220fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc); 1023421f2f7dSMike Smith *arg = 0x0106; 10241ac4b82bSMike Smith return(EBUSY); 1025421f2f7dSMike Smith } 1026421f2f7dSMike Smith result = mlx_check(sc, drive - &sc->mlx_sysdrive[0]); 1027421f2f7dSMike Smith switch (result) { 10281ac4b82bSMike Smith case 0: 10291ac4b82bSMike Smith error = 0; 10301ac4b82bSMike Smith break; 10311ac4b82bSMike Smith case 0x10000: 10321ac4b82bSMike Smith error = ENOMEM; /* couldn't set up the command */ 10331ac4b82bSMike Smith break; 10341ac4b82bSMike Smith case 0x0002: 10351ac4b82bSMike Smith error = EIO; 10361ac4b82bSMike Smith break; 10371ac4b82bSMike Smith case 0x0105: 10381ac4b82bSMike Smith error = ERANGE; 10391ac4b82bSMike Smith break; 1040421f2f7dSMike Smith case 0x0106: 1041421f2f7dSMike Smith error = EBUSY; 1042421f2f7dSMike Smith break; 10431ac4b82bSMike Smith default: 10441ac4b82bSMike Smith error = EINVAL; 10451ac4b82bSMike Smith break; 10461ac4b82bSMike Smith } 1047421f2f7dSMike Smith if (error == 0) 1048421f2f7dSMike Smith sc->mlx_background = MLX_BACKGROUND_CHECK; 10490fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc); 1050421f2f7dSMike Smith *arg = result; 10511ac4b82bSMike Smith return(error); 10521ac4b82bSMike Smith 10531ac4b82bSMike Smith } 10541ac4b82bSMike Smith return(ENOIOCTL); 10551ac4b82bSMike Smith } 10561ac4b82bSMike Smith 10571ac4b82bSMike Smith 10581ac4b82bSMike Smith /******************************************************************************** 10591ac4b82bSMike Smith ******************************************************************************** 10601ac4b82bSMike Smith Status Monitoring 10611ac4b82bSMike Smith ******************************************************************************** 10621ac4b82bSMike Smith ********************************************************************************/ 10631ac4b82bSMike Smith 10641ac4b82bSMike Smith /******************************************************************************** 10651ac4b82bSMike Smith * Fire off commands to periodically check the status of connected drives. 10661ac4b82bSMike Smith */ 10671ac4b82bSMike Smith static void 10681ac4b82bSMike Smith mlx_periodic(void *data) 10691ac4b82bSMike Smith { 10701ac4b82bSMike Smith struct mlx_softc *sc = (struct mlx_softc *)data; 10711ac4b82bSMike Smith 1072da8bb3a3SMike Smith debug_called(1); 10730fca6f8bSJohn Baldwin MLX_IO_ASSERT_LOCKED(sc); 10741ac4b82bSMike Smith 10751ac4b82bSMike Smith /* 10761ac4b82bSMike Smith * Run a bus pause? 10771ac4b82bSMike Smith */ 10781ac4b82bSMike Smith if ((sc->mlx_pause.mp_which != 0) && 10791ac4b82bSMike Smith (sc->mlx_pause.mp_when > 0) && 10801ac4b82bSMike Smith (time_second >= sc->mlx_pause.mp_when)){ 10811ac4b82bSMike Smith 10821ac4b82bSMike Smith mlx_pause_action(sc); /* pause is running */ 10831ac4b82bSMike Smith sc->mlx_pause.mp_when = 0; 10841ac4b82bSMike Smith sysbeep(500, hz); 10851ac4b82bSMike Smith 10861ac4b82bSMike Smith /* 10871ac4b82bSMike Smith * Bus pause still running? 10881ac4b82bSMike Smith */ 10891ac4b82bSMike Smith } else if ((sc->mlx_pause.mp_which != 0) && 10901ac4b82bSMike Smith (sc->mlx_pause.mp_when == 0)) { 10911ac4b82bSMike Smith 10921ac4b82bSMike Smith /* time to stop bus pause? */ 10931ac4b82bSMike Smith if (time_second >= sc->mlx_pause.mp_howlong) { 10941ac4b82bSMike Smith mlx_pause_action(sc); 10951ac4b82bSMike Smith sc->mlx_pause.mp_which = 0; /* pause is complete */ 10961ac4b82bSMike Smith sysbeep(500, hz); 10971ac4b82bSMike Smith } else { 10981ac4b82bSMike Smith sysbeep((time_second % 5) * 100 + 500, hz/8); 10991ac4b82bSMike Smith } 11001ac4b82bSMike Smith 11011ac4b82bSMike Smith /* 11021ac4b82bSMike Smith * Run normal periodic activities? 11031ac4b82bSMike Smith */ 11045792b7feSMike Smith } else if (time_second > (sc->mlx_lastpoll + 10)) { 11051ac4b82bSMike Smith sc->mlx_lastpoll = time_second; 11061ac4b82bSMike Smith 11071ac4b82bSMike Smith /* 11081ac4b82bSMike Smith * Check controller status. 11095792b7feSMike Smith * 11105792b7feSMike Smith * XXX Note that this may not actually launch a command in situations of high load. 11111ac4b82bSMike Smith */ 1112da8bb3a3SMike Smith mlx_enquire(sc, (sc->mlx_iftype == MLX_IFTYPE_2) ? MLX_CMD_ENQUIRY_OLD : MLX_CMD_ENQUIRY, 1113da8bb3a3SMike Smith imax(sizeof(struct mlx_enquiry), sizeof(struct mlx_enquiry_old)), mlx_periodic_enquiry); 11141ac4b82bSMike Smith 11151ac4b82bSMike Smith /* 11161ac4b82bSMike Smith * Check system drive status. 11171ac4b82bSMike Smith * 11181ac4b82bSMike Smith * XXX This might be better left to event-driven detection, eg. I/O to an offline 11191ac4b82bSMike Smith * drive will detect it's offline, rebuilds etc. should detect the drive is back 11201ac4b82bSMike Smith * online. 11211ac4b82bSMike Smith */ 11221ac4b82bSMike Smith mlx_enquire(sc, MLX_CMD_ENQSYSDRIVE, sizeof(struct mlx_enq_sys_drive) * MLX_MAXDRIVES, 11231ac4b82bSMike Smith mlx_periodic_enquiry); 11241ac4b82bSMike Smith 11251ac4b82bSMike Smith } 11261ac4b82bSMike Smith 1127421f2f7dSMike Smith /* get drive rebuild/check status */ 1128421f2f7dSMike Smith /* XXX should check sc->mlx_background if this is only valid while in progress */ 1129421f2f7dSMike Smith mlx_enquire(sc, MLX_CMD_REBUILDSTAT, sizeof(struct mlx_rebuild_stat), mlx_periodic_rebuild); 1130421f2f7dSMike Smith 11315792b7feSMike Smith /* deal with possibly-missed interrupts and timed-out commands */ 11320fca6f8bSJohn Baldwin mlx_done(sc, 1); 11331ac4b82bSMike Smith 11341ac4b82bSMike Smith /* reschedule another poll next second or so */ 11350fca6f8bSJohn Baldwin callout_reset(&sc->mlx_timeout, hz, mlx_periodic, sc); 11361ac4b82bSMike Smith } 11371ac4b82bSMike Smith 11381ac4b82bSMike Smith /******************************************************************************** 11391ac4b82bSMike Smith * Handle the result of an ENQUIRY command instigated by periodic status polling. 11401ac4b82bSMike Smith */ 11411ac4b82bSMike Smith static void 11421ac4b82bSMike Smith mlx_periodic_enquiry(struct mlx_command *mc) 11431ac4b82bSMike Smith { 11441ac4b82bSMike Smith struct mlx_softc *sc = mc->mc_sc; 11451ac4b82bSMike Smith 1146da8bb3a3SMike Smith debug_called(1); 11470fca6f8bSJohn Baldwin MLX_IO_ASSERT_LOCKED(sc); 11481ac4b82bSMike Smith 11491ac4b82bSMike Smith /* Command completed OK? */ 11501ac4b82bSMike Smith if (mc->mc_status != 0) { 1151da8bb3a3SMike Smith device_printf(sc->mlx_dev, "periodic enquiry failed - %s\n", mlx_diagnose_command(mc)); 11521ac4b82bSMike Smith goto out; 11531ac4b82bSMike Smith } 11541ac4b82bSMike Smith 11551ac4b82bSMike Smith /* respond to command */ 11561ac4b82bSMike Smith switch(mc->mc_mailbox[0]) { 11571ac4b82bSMike Smith /* 1158da8bb3a3SMike Smith * This is currently a bit fruitless, as we don't know how to extract the eventlog 1159da8bb3a3SMike Smith * pointer yet. 1160da8bb3a3SMike Smith */ 1161da8bb3a3SMike Smith case MLX_CMD_ENQUIRY_OLD: 1162da8bb3a3SMike Smith { 1163da8bb3a3SMike Smith struct mlx_enquiry *me = (struct mlx_enquiry *)mc->mc_data; 1164da8bb3a3SMike Smith struct mlx_enquiry_old *meo = (struct mlx_enquiry_old *)mc->mc_data; 1165da8bb3a3SMike Smith int i; 1166da8bb3a3SMike Smith 1167da8bb3a3SMike Smith /* convert data in-place to new format */ 1168da8bb3a3SMike Smith for (i = (sizeof(me->me_dead) / sizeof(me->me_dead[0])) - 1; i >= 0; i--) { 1169da8bb3a3SMike Smith me->me_dead[i].dd_chan = meo->me_dead[i].dd_chan; 1170da8bb3a3SMike Smith me->me_dead[i].dd_targ = meo->me_dead[i].dd_targ; 1171da8bb3a3SMike Smith } 1172da8bb3a3SMike Smith me->me_misc_flags = 0; 1173da8bb3a3SMike Smith me->me_rebuild_count = meo->me_rebuild_count; 1174da8bb3a3SMike Smith me->me_dead_count = meo->me_dead_count; 1175da8bb3a3SMike Smith me->me_critical_sd_count = meo->me_critical_sd_count; 1176da8bb3a3SMike Smith me->me_event_log_seq_num = 0; 1177da8bb3a3SMike Smith me->me_offline_sd_count = meo->me_offline_sd_count; 1178da8bb3a3SMike Smith me->me_max_commands = meo->me_max_commands; 1179da8bb3a3SMike Smith me->me_rebuild_flag = meo->me_rebuild_flag; 1180da8bb3a3SMike Smith me->me_fwmajor = meo->me_fwmajor; 1181da8bb3a3SMike Smith me->me_fwminor = meo->me_fwminor; 1182da8bb3a3SMike Smith me->me_status_flags = meo->me_status_flags; 1183da8bb3a3SMike Smith me->me_flash_age = meo->me_flash_age; 1184da8bb3a3SMike Smith for (i = (sizeof(me->me_drvsize) / sizeof(me->me_drvsize[0])) - 1; i >= 0; i--) { 1185da8bb3a3SMike Smith if (i > ((sizeof(meo->me_drvsize) / sizeof(meo->me_drvsize[0])) - 1)) { 1186da8bb3a3SMike Smith me->me_drvsize[i] = 0; /* drive beyond supported range */ 1187da8bb3a3SMike Smith } else { 1188da8bb3a3SMike Smith me->me_drvsize[i] = meo->me_drvsize[i]; 1189da8bb3a3SMike Smith } 1190da8bb3a3SMike Smith } 1191da8bb3a3SMike Smith me->me_num_sys_drvs = meo->me_num_sys_drvs; 1192da8bb3a3SMike Smith } 1193da8bb3a3SMike Smith /* FALLTHROUGH */ 1194da8bb3a3SMike Smith 1195da8bb3a3SMike Smith /* 11961ac4b82bSMike Smith * Generic controller status update. We could do more with this than just 11971ac4b82bSMike Smith * checking the event log. 11981ac4b82bSMike Smith */ 11991ac4b82bSMike Smith case MLX_CMD_ENQUIRY: 12001ac4b82bSMike Smith { 12011ac4b82bSMike Smith struct mlx_enquiry *me = (struct mlx_enquiry *)mc->mc_data; 12021ac4b82bSMike Smith 1203421f2f7dSMike Smith if (sc->mlx_currevent == -1) { 12049eee27f1SMike Smith /* initialise our view of the event log */ 12059eee27f1SMike Smith sc->mlx_currevent = sc->mlx_lastevent = me->me_event_log_seq_num; 12065d278f5cSMike Smith } else if ((me->me_event_log_seq_num != sc->mlx_lastevent) && !(sc->mlx_flags & MLX_EVENTLOG_BUSY)) { 12071ac4b82bSMike Smith /* record where current events are up to */ 12081ac4b82bSMike Smith sc->mlx_currevent = me->me_event_log_seq_num; 1209da8bb3a3SMike Smith debug(1, "event log pointer was %d, now %d\n", sc->mlx_lastevent, sc->mlx_currevent); 12101ac4b82bSMike Smith 12115d278f5cSMike Smith /* mark the event log as busy */ 12120fca6f8bSJohn Baldwin sc->mlx_flags |= MLX_EVENTLOG_BUSY; 12135d278f5cSMike Smith 12149eee27f1SMike Smith /* drain new eventlog entries */ 12151ac4b82bSMike Smith mlx_periodic_eventlog_poll(sc); 12161ac4b82bSMike Smith } 12171ac4b82bSMike Smith break; 12181ac4b82bSMike Smith } 12191ac4b82bSMike Smith case MLX_CMD_ENQSYSDRIVE: 12201ac4b82bSMike Smith { 12211ac4b82bSMike Smith struct mlx_enq_sys_drive *mes = (struct mlx_enq_sys_drive *)mc->mc_data; 12221ac4b82bSMike Smith struct mlx_sysdrive *dr; 12231ac4b82bSMike Smith int i; 12241ac4b82bSMike Smith 12251ac4b82bSMike Smith for (i = 0, dr = &sc->mlx_sysdrive[0]; 12261ac4b82bSMike Smith (i < MLX_MAXDRIVES) && (mes[i].sd_size != 0xffffffff); 12271ac4b82bSMike Smith i++) { 12281ac4b82bSMike Smith 12291ac4b82bSMike Smith /* has state been changed by controller? */ 12301ac4b82bSMike Smith if (dr->ms_state != mes[i].sd_state) { 12311ac4b82bSMike Smith switch(mes[i].sd_state) { 12321ac4b82bSMike Smith case MLX_SYSD_OFFLINE: 12331ac4b82bSMike Smith device_printf(dr->ms_disk, "drive offline\n"); 12341ac4b82bSMike Smith break; 12351ac4b82bSMike Smith case MLX_SYSD_ONLINE: 12361ac4b82bSMike Smith device_printf(dr->ms_disk, "drive online\n"); 12371ac4b82bSMike Smith break; 12381ac4b82bSMike Smith case MLX_SYSD_CRITICAL: 12391ac4b82bSMike Smith device_printf(dr->ms_disk, "drive critical\n"); 12401ac4b82bSMike Smith break; 12411ac4b82bSMike Smith } 12421ac4b82bSMike Smith /* save new state */ 12431ac4b82bSMike Smith dr->ms_state = mes[i].sd_state; 12441ac4b82bSMike Smith } 12451ac4b82bSMike Smith } 12461ac4b82bSMike Smith break; 12471ac4b82bSMike Smith } 12481ac4b82bSMike Smith default: 12496e551fb6SDavid E. O'Brien device_printf(sc->mlx_dev, "%s: unknown command 0x%x", __func__, mc->mc_mailbox[0]); 12501ac4b82bSMike Smith break; 12511ac4b82bSMike Smith } 12521ac4b82bSMike Smith 12531ac4b82bSMike Smith out: 12541ac4b82bSMike Smith free(mc->mc_data, M_DEVBUF); 12551ac4b82bSMike Smith mlx_releasecmd(mc); 12561ac4b82bSMike Smith } 12571ac4b82bSMike Smith 12581b4404f9SScott Long static void 12591b4404f9SScott Long mlx_eventlog_cb(void *arg, bus_dma_segment_t *segs, int nsegments, int error) 12601b4404f9SScott Long { 12611b4404f9SScott Long struct mlx_command *mc; 12621b4404f9SScott Long 12631b4404f9SScott Long mc = (struct mlx_command *)arg; 12641b4404f9SScott Long mlx_setup_dmamap(mc, segs, nsegments, error); 12651b4404f9SScott Long 12661b4404f9SScott Long /* build the command to get one entry */ 12671b4404f9SScott Long mlx_make_type3(mc, MLX_CMD_LOGOP, MLX_LOGOP_GET, 1, 12681b4404f9SScott Long mc->mc_sc->mlx_lastevent, 0, 0, mc->mc_dataphys, 0); 12691b4404f9SScott Long mc->mc_complete = mlx_periodic_eventlog_respond; 12701b4404f9SScott Long mc->mc_private = mc; 12711b4404f9SScott Long 12721b4404f9SScott Long /* start the command */ 12731b4404f9SScott Long if (mlx_start(mc) != 0) { 12741b4404f9SScott Long mlx_releasecmd(mc); 12751b4404f9SScott Long free(mc->mc_data, M_DEVBUF); 12761b4404f9SScott Long mc->mc_data = NULL; 12771b4404f9SScott Long } 12781b4404f9SScott Long 12791b4404f9SScott Long } 12801b4404f9SScott Long 12811ac4b82bSMike Smith /******************************************************************************** 12821ac4b82bSMike Smith * Instigate a poll for one event log message on (sc). 12831ac4b82bSMike Smith * We only poll for one message at a time, to keep our command usage down. 12841ac4b82bSMike Smith */ 12851ac4b82bSMike Smith static void 12861ac4b82bSMike Smith mlx_periodic_eventlog_poll(struct mlx_softc *sc) 12871ac4b82bSMike Smith { 12881ac4b82bSMike Smith struct mlx_command *mc; 12891ac4b82bSMike Smith void *result = NULL; 12901b4404f9SScott Long int error = 0; 12911ac4b82bSMike Smith 1292da8bb3a3SMike Smith debug_called(1); 12930fca6f8bSJohn Baldwin MLX_IO_ASSERT_LOCKED(sc); 12941ac4b82bSMike Smith 12951ac4b82bSMike Smith /* get ourselves a command buffer */ 12961ac4b82bSMike Smith error = 1; 12971ac4b82bSMike Smith if ((mc = mlx_alloccmd(sc)) == NULL) 12981ac4b82bSMike Smith goto out; 12991b4404f9SScott Long 13001ac4b82bSMike Smith /* allocate the response structure */ 13011b4404f9SScott Long if ((result = malloc(/*sizeof(struct mlx_eventlog_entry)*/1024, M_DEVBUF, 13021b4404f9SScott Long M_NOWAIT)) == NULL) 13031ac4b82bSMike Smith goto out; 13041b4404f9SScott Long 13051ac4b82bSMike Smith /* get a command slot */ 13061ac4b82bSMike Smith if (mlx_getslot(mc)) 13071ac4b82bSMike Smith goto out; 13081ac4b82bSMike Smith 13091ac4b82bSMike Smith /* map the command so the controller can see it */ 13101ac4b82bSMike Smith mc->mc_data = result; 131133c8cb18SMike Smith mc->mc_length = /*sizeof(struct mlx_eventlog_entry)*/1024; 13121b4404f9SScott Long error = bus_dmamap_load(sc->mlx_buffer_dmat, mc->mc_dmamap, mc->mc_data, 13131b4404f9SScott Long mc->mc_length, mlx_eventlog_cb, mc, BUS_DMA_NOWAIT); 13141ac4b82bSMike Smith 13151ac4b82bSMike Smith out: 131633c8cb18SMike Smith if (error != 0) { 13171ac4b82bSMike Smith if (mc != NULL) 13181ac4b82bSMike Smith mlx_releasecmd(mc); 13191b4404f9SScott Long if ((result != NULL) && (mc->mc_data != NULL)) 13201ac4b82bSMike Smith free(result, M_DEVBUF); 13211ac4b82bSMike Smith } 132233c8cb18SMike Smith } 13231ac4b82bSMike Smith 13241ac4b82bSMike Smith /******************************************************************************** 13251ac4b82bSMike Smith * Handle the result of polling for a log message, generate diagnostic output. 13261ac4b82bSMike Smith * If this wasn't the last message waiting for us, we'll go collect another. 13271ac4b82bSMike Smith */ 13281ac4b82bSMike Smith static char *mlx_sense_messages[] = { 13291ac4b82bSMike Smith "because write recovery failed", 13301ac4b82bSMike Smith "because of SCSI bus reset failure", 13311ac4b82bSMike Smith "because of double check condition", 13321ac4b82bSMike Smith "because it was removed", 13331ac4b82bSMike Smith "because of gross error on SCSI chip", 13341ac4b82bSMike Smith "because of bad tag returned from drive", 13351ac4b82bSMike Smith "because of timeout on SCSI command", 13361ac4b82bSMike Smith "because of reset SCSI command issued from system", 13371ac4b82bSMike Smith "because busy or parity error count exceeded limit", 13381ac4b82bSMike Smith "because of 'kill drive' command from system", 13391ac4b82bSMike Smith "because of selection timeout", 13401ac4b82bSMike Smith "due to SCSI phase sequence error", 13411ac4b82bSMike Smith "due to unknown status" 13421ac4b82bSMike Smith }; 13431ac4b82bSMike Smith 13441ac4b82bSMike Smith static void 13451ac4b82bSMike Smith mlx_periodic_eventlog_respond(struct mlx_command *mc) 13461ac4b82bSMike Smith { 13471ac4b82bSMike Smith struct mlx_softc *sc = mc->mc_sc; 13481ac4b82bSMike Smith struct mlx_eventlog_entry *el = (struct mlx_eventlog_entry *)mc->mc_data; 13491ac4b82bSMike Smith char *reason; 13501ac4b82bSMike Smith 1351da8bb3a3SMike Smith debug_called(1); 13520fca6f8bSJohn Baldwin MLX_IO_ASSERT_LOCKED(sc); 13531ac4b82bSMike Smith 13545792b7feSMike Smith sc->mlx_lastevent++; /* next message... */ 13551ac4b82bSMike Smith if (mc->mc_status == 0) { 13561ac4b82bSMike Smith 13571ac4b82bSMike Smith /* handle event log message */ 13581ac4b82bSMike Smith switch(el->el_type) { 13591ac4b82bSMike Smith /* 13601ac4b82bSMike Smith * This is the only sort of message we understand at the moment. 13611ac4b82bSMike Smith * The tests here are probably incomplete. 13621ac4b82bSMike Smith */ 13631ac4b82bSMike Smith case MLX_LOGMSG_SENSE: /* sense data */ 13641ac4b82bSMike Smith /* Mylex vendor-specific message indicating a drive was killed? */ 13651ac4b82bSMike Smith if ((el->el_sensekey == 9) && 13661ac4b82bSMike Smith (el->el_asc == 0x80)) { 1367*73a1170aSPedro F. Giffuni if (el->el_asq < nitems(mlx_sense_messages)) { 13681ac4b82bSMike Smith reason = mlx_sense_messages[el->el_asq]; 13691ac4b82bSMike Smith } else { 13701ac4b82bSMike Smith reason = "for unknown reason"; 13711ac4b82bSMike Smith } 13721ac4b82bSMike Smith device_printf(sc->mlx_dev, "physical drive %d:%d killed %s\n", 13731ac4b82bSMike Smith el->el_channel, el->el_target, reason); 13741ac4b82bSMike Smith } 13751ac4b82bSMike Smith /* SCSI drive was reset? */ 13761ac4b82bSMike Smith if ((el->el_sensekey == 6) && (el->el_asc == 0x29)) { 13771ac4b82bSMike Smith device_printf(sc->mlx_dev, "physical drive %d:%d reset\n", 13781ac4b82bSMike Smith el->el_channel, el->el_target); 13791ac4b82bSMike Smith } 13801ac4b82bSMike Smith /* SCSI drive error? */ 13811ac4b82bSMike Smith if (!((el->el_sensekey == 0) || 13821ac4b82bSMike Smith ((el->el_sensekey == 2) && 13831ac4b82bSMike Smith (el->el_asc == 0x04) && 13841ac4b82bSMike Smith ((el->el_asq == 0x01) || 13851ac4b82bSMike Smith (el->el_asq == 0x02))))) { 13861ac4b82bSMike Smith device_printf(sc->mlx_dev, "physical drive %d:%d error log: sense = %d asc = %x asq = %x\n", 13871ac4b82bSMike Smith el->el_channel, el->el_target, el->el_sensekey, el->el_asc, el->el_asq); 13881ac4b82bSMike Smith device_printf(sc->mlx_dev, " info %4D csi %4D\n", el->el_information, ":", el->el_csi, ":"); 13891ac4b82bSMike Smith } 13901ac4b82bSMike Smith break; 13911ac4b82bSMike Smith 13921ac4b82bSMike Smith default: 13931ac4b82bSMike Smith device_printf(sc->mlx_dev, "unknown log message type 0x%x\n", el->el_type); 13941ac4b82bSMike Smith break; 13951ac4b82bSMike Smith } 13961ac4b82bSMike Smith } else { 13971ac4b82bSMike Smith device_printf(sc->mlx_dev, "error reading message log - %s\n", mlx_diagnose_command(mc)); 13985d278f5cSMike Smith /* give up on all the outstanding messages, as we may have come unsynched */ 13995d278f5cSMike Smith sc->mlx_lastevent = sc->mlx_currevent; 14001ac4b82bSMike Smith } 14011ac4b82bSMike Smith 14021ac4b82bSMike Smith /* dispose of command and data */ 14031ac4b82bSMike Smith free(mc->mc_data, M_DEVBUF); 14041ac4b82bSMike Smith mlx_releasecmd(mc); 14051ac4b82bSMike Smith 14061ac4b82bSMike Smith /* is there another message to obtain? */ 14075d278f5cSMike Smith if (sc->mlx_lastevent != sc->mlx_currevent) { 14081ac4b82bSMike Smith mlx_periodic_eventlog_poll(sc); 14095d278f5cSMike Smith } else { 14105d278f5cSMike Smith /* clear log-busy status */ 14110fca6f8bSJohn Baldwin sc->mlx_flags &= ~MLX_EVENTLOG_BUSY; 14125d278f5cSMike Smith } 14131ac4b82bSMike Smith } 14141ac4b82bSMike Smith 14151ac4b82bSMike Smith /******************************************************************************** 1416421f2f7dSMike Smith * Handle check/rebuild operations in progress. 14171ac4b82bSMike Smith */ 14181ac4b82bSMike Smith static void 14191ac4b82bSMike Smith mlx_periodic_rebuild(struct mlx_command *mc) 14201ac4b82bSMike Smith { 14211ac4b82bSMike Smith struct mlx_softc *sc = mc->mc_sc; 1422421f2f7dSMike Smith struct mlx_rebuild_status *mr = (struct mlx_rebuild_status *)mc->mc_data; 14231ac4b82bSMike Smith 14240fca6f8bSJohn Baldwin MLX_IO_ASSERT_LOCKED(sc); 14251ac4b82bSMike Smith switch(mc->mc_status) { 1426421f2f7dSMike Smith case 0: /* operation running, update stats */ 1427421f2f7dSMike Smith sc->mlx_rebuildstat = *mr; 1428421f2f7dSMike Smith 1429421f2f7dSMike Smith /* spontaneous rebuild/check? */ 1430421f2f7dSMike Smith if (sc->mlx_background == 0) { 1431421f2f7dSMike Smith sc->mlx_background = MLX_BACKGROUND_SPONTANEOUS; 1432421f2f7dSMike Smith device_printf(sc->mlx_dev, "background check/rebuild operation started\n"); 1433421f2f7dSMike Smith } 14341ac4b82bSMike Smith break; 14351ac4b82bSMike Smith 1436421f2f7dSMike Smith case 0x0105: /* nothing running, finalise stats and report */ 1437421f2f7dSMike Smith switch(sc->mlx_background) { 1438421f2f7dSMike Smith case MLX_BACKGROUND_CHECK: 1439421f2f7dSMike Smith device_printf(sc->mlx_dev, "consistency check completed\n"); /* XXX print drive? */ 1440421f2f7dSMike Smith break; 1441421f2f7dSMike Smith case MLX_BACKGROUND_REBUILD: 1442421f2f7dSMike Smith device_printf(sc->mlx_dev, "drive rebuild completed\n"); /* XXX print channel/target? */ 1443421f2f7dSMike Smith break; 1444421f2f7dSMike Smith case MLX_BACKGROUND_SPONTANEOUS: 1445421f2f7dSMike Smith default: 1446421f2f7dSMike Smith /* if we have previously been non-idle, report the transition */ 1447421f2f7dSMike Smith if (sc->mlx_rebuildstat.rs_code != MLX_REBUILDSTAT_IDLE) { 1448421f2f7dSMike Smith device_printf(sc->mlx_dev, "background check/rebuild operation completed\n"); 14491ac4b82bSMike Smith } 1450421f2f7dSMike Smith } 1451421f2f7dSMike Smith sc->mlx_background = 0; 1452421f2f7dSMike Smith sc->mlx_rebuildstat.rs_code = MLX_REBUILDSTAT_IDLE; 14531ac4b82bSMike Smith break; 14541ac4b82bSMike Smith } 14551ac4b82bSMike Smith free(mc->mc_data, M_DEVBUF); 14561ac4b82bSMike Smith mlx_releasecmd(mc); 14571ac4b82bSMike Smith } 14581ac4b82bSMike Smith 14591ac4b82bSMike Smith /******************************************************************************** 14601ac4b82bSMike Smith ******************************************************************************** 14611ac4b82bSMike Smith Channel Pause 14621ac4b82bSMike Smith ******************************************************************************** 14631ac4b82bSMike Smith ********************************************************************************/ 14641ac4b82bSMike Smith 14651ac4b82bSMike Smith /******************************************************************************** 14661ac4b82bSMike Smith * It's time to perform a channel pause action for (sc), either start or stop 14671ac4b82bSMike Smith * the pause. 14681ac4b82bSMike Smith */ 14691ac4b82bSMike Smith static void 14701ac4b82bSMike Smith mlx_pause_action(struct mlx_softc *sc) 14711ac4b82bSMike Smith { 14721ac4b82bSMike Smith struct mlx_command *mc; 14731ac4b82bSMike Smith int failsafe, i, command; 14741ac4b82bSMike Smith 14750fca6f8bSJohn Baldwin MLX_IO_ASSERT_LOCKED(sc); 14760fca6f8bSJohn Baldwin 14771ac4b82bSMike Smith /* What are we doing here? */ 14781ac4b82bSMike Smith if (sc->mlx_pause.mp_when == 0) { 14791ac4b82bSMike Smith command = MLX_CMD_STARTCHANNEL; 14801ac4b82bSMike Smith failsafe = 0; 14811ac4b82bSMike Smith 14821ac4b82bSMike Smith } else { 14831ac4b82bSMike Smith command = MLX_CMD_STOPCHANNEL; 14841ac4b82bSMike Smith 14851ac4b82bSMike Smith /* 14861ac4b82bSMike Smith * Channels will always start again after the failsafe period, 14871ac4b82bSMike Smith * which is specified in multiples of 30 seconds. 14881ac4b82bSMike Smith * This constrains us to a maximum pause of 450 seconds. 14891ac4b82bSMike Smith */ 14901ac4b82bSMike Smith failsafe = ((sc->mlx_pause.mp_howlong - time_second) + 5) / 30; 14911ac4b82bSMike Smith if (failsafe > 0xf) { 14921ac4b82bSMike Smith failsafe = 0xf; 14931ac4b82bSMike Smith sc->mlx_pause.mp_howlong = time_second + (0xf * 30) - 5; 14941ac4b82bSMike Smith } 14951ac4b82bSMike Smith } 14961ac4b82bSMike Smith 14971ac4b82bSMike Smith /* build commands for every channel requested */ 14989eee27f1SMike Smith for (i = 0; i < sc->mlx_enq2->me_actual_channels; i++) { 14991ac4b82bSMike Smith if ((1 << i) & sc->mlx_pause.mp_which) { 15001ac4b82bSMike Smith 15011ac4b82bSMike Smith /* get ourselves a command buffer */ 15021ac4b82bSMike Smith if ((mc = mlx_alloccmd(sc)) == NULL) 15031ac4b82bSMike Smith goto fail; 15041ac4b82bSMike Smith /* get a command slot */ 15051ac4b82bSMike Smith mc->mc_flags |= MLX_CMD_PRIORITY; 15061ac4b82bSMike Smith if (mlx_getslot(mc)) 15071ac4b82bSMike Smith goto fail; 15081ac4b82bSMike Smith 15091ac4b82bSMike Smith /* build the command */ 15101ac4b82bSMike Smith mlx_make_type2(mc, command, (failsafe << 4) | i, 0, 0, 0, 0, 0, 0, 0); 15111ac4b82bSMike Smith mc->mc_complete = mlx_pause_done; 15121ac4b82bSMike Smith mc->mc_private = sc; /* XXX not needed */ 15131ac4b82bSMike Smith if (mlx_start(mc)) 15141ac4b82bSMike Smith goto fail; 15151ac4b82bSMike Smith /* command submitted OK */ 15161ac4b82bSMike Smith return; 15171ac4b82bSMike Smith 15181ac4b82bSMike Smith fail: 15191ac4b82bSMike Smith device_printf(sc->mlx_dev, "%s failed for channel %d\n", 15201ac4b82bSMike Smith command == MLX_CMD_STOPCHANNEL ? "pause" : "resume", i); 15211ac4b82bSMike Smith if (mc != NULL) 15221ac4b82bSMike Smith mlx_releasecmd(mc); 15231ac4b82bSMike Smith } 15241ac4b82bSMike Smith } 15251ac4b82bSMike Smith } 15261ac4b82bSMike Smith 15271ac4b82bSMike Smith static void 15281ac4b82bSMike Smith mlx_pause_done(struct mlx_command *mc) 15291ac4b82bSMike Smith { 15301ac4b82bSMike Smith struct mlx_softc *sc = mc->mc_sc; 15311ac4b82bSMike Smith int command = mc->mc_mailbox[0]; 15321ac4b82bSMike Smith int channel = mc->mc_mailbox[2] & 0xf; 15331ac4b82bSMike Smith 15340fca6f8bSJohn Baldwin MLX_IO_ASSERT_LOCKED(sc); 15351ac4b82bSMike Smith if (mc->mc_status != 0) { 15361ac4b82bSMike Smith device_printf(sc->mlx_dev, "%s command failed - %s\n", 15371ac4b82bSMike Smith command == MLX_CMD_STOPCHANNEL ? "pause" : "resume", mlx_diagnose_command(mc)); 15381ac4b82bSMike Smith } else if (command == MLX_CMD_STOPCHANNEL) { 15391ac4b82bSMike Smith device_printf(sc->mlx_dev, "channel %d pausing for %ld seconds\n", 154072c10febSPeter Wemm channel, (long)(sc->mlx_pause.mp_howlong - time_second)); 15411ac4b82bSMike Smith } else { 15421ac4b82bSMike Smith device_printf(sc->mlx_dev, "channel %d resuming\n", channel); 15431ac4b82bSMike Smith } 15441ac4b82bSMike Smith mlx_releasecmd(mc); 15451ac4b82bSMike Smith } 15461ac4b82bSMike Smith 15471ac4b82bSMike Smith /******************************************************************************** 15481ac4b82bSMike Smith ******************************************************************************** 15491ac4b82bSMike Smith Command Submission 15501ac4b82bSMike Smith ******************************************************************************** 15511ac4b82bSMike Smith ********************************************************************************/ 15521ac4b82bSMike Smith 15531b4404f9SScott Long static void 15541b4404f9SScott Long mlx_enquire_cb(void *arg, bus_dma_segment_t *segs, int nsegments, int error) 15551b4404f9SScott Long { 15561b4404f9SScott Long struct mlx_softc *sc; 15571b4404f9SScott Long struct mlx_command *mc; 15581b4404f9SScott Long 15591b4404f9SScott Long mc = (struct mlx_command *)arg; 15601b4404f9SScott Long if (error) 15611b4404f9SScott Long return; 15621b4404f9SScott Long 15631b4404f9SScott Long mlx_setup_dmamap(mc, segs, nsegments, error); 15641b4404f9SScott Long 15651b4404f9SScott Long /* build an enquiry command */ 15661b4404f9SScott Long sc = mc->mc_sc; 15671b4404f9SScott Long mlx_make_type2(mc, mc->mc_command, 0, 0, 0, 0, 0, 0, mc->mc_dataphys, 0); 15681b4404f9SScott Long 15691b4404f9SScott Long /* do we want a completion callback? */ 15701b4404f9SScott Long if (mc->mc_complete != NULL) { 15711b4404f9SScott Long if ((error = mlx_start(mc)) != 0) 15721b4404f9SScott Long return; 15731b4404f9SScott Long } else { 15741b4404f9SScott Long /* run the command in either polled or wait mode */ 15751b4404f9SScott Long if ((sc->mlx_state & MLX_STATE_INTEN) ? mlx_wait_command(mc) : 15761b4404f9SScott Long mlx_poll_command(mc)) 15771b4404f9SScott Long return; 15781b4404f9SScott Long 15791b4404f9SScott Long /* command completed OK? */ 15801b4404f9SScott Long if (mc->mc_status != 0) { 15811b4404f9SScott Long device_printf(sc->mlx_dev, "ENQUIRY failed - %s\n", 15821b4404f9SScott Long mlx_diagnose_command(mc)); 15831b4404f9SScott Long return; 15841b4404f9SScott Long } 15851b4404f9SScott Long } 15861b4404f9SScott Long } 15871b4404f9SScott Long 15881ac4b82bSMike Smith /******************************************************************************** 15891ac4b82bSMike Smith * Perform an Enquiry command using a type-3 command buffer and a return a single 15901ac4b82bSMike Smith * linear result buffer. If the completion function is specified, it will 15911ac4b82bSMike Smith * be called with the completed command (and the result response will not be 15921ac4b82bSMike Smith * valid until that point). Otherwise, the command will either be busy-waited 15931ac4b82bSMike Smith * for (interrupts not enabled), or slept for. 15941ac4b82bSMike Smith */ 15951ac4b82bSMike Smith static void * 15961ac4b82bSMike Smith mlx_enquire(struct mlx_softc *sc, int command, size_t bufsize, void (* complete)(struct mlx_command *mc)) 15971ac4b82bSMike Smith { 15981ac4b82bSMike Smith struct mlx_command *mc; 15991ac4b82bSMike Smith void *result; 16001ac4b82bSMike Smith int error; 16011ac4b82bSMike Smith 1602da8bb3a3SMike Smith debug_called(1); 16030fca6f8bSJohn Baldwin MLX_IO_ASSERT_LOCKED(sc); 16041ac4b82bSMike Smith 16051ac4b82bSMike Smith /* get ourselves a command buffer */ 16061ac4b82bSMike Smith error = 1; 16071ac4b82bSMike Smith result = NULL; 16081ac4b82bSMike Smith if ((mc = mlx_alloccmd(sc)) == NULL) 16091ac4b82bSMike Smith goto out; 16101ac4b82bSMike Smith /* allocate the response structure */ 16111ac4b82bSMike Smith if ((result = malloc(bufsize, M_DEVBUF, M_NOWAIT)) == NULL) 16121ac4b82bSMike Smith goto out; 16131ac4b82bSMike Smith /* get a command slot */ 16141ac4b82bSMike Smith mc->mc_flags |= MLX_CMD_PRIORITY | MLX_CMD_DATAOUT; 16151ac4b82bSMike Smith if (mlx_getslot(mc)) 16161ac4b82bSMike Smith goto out; 16171ac4b82bSMike Smith 16181ac4b82bSMike Smith /* map the command so the controller can see it */ 16191ac4b82bSMike Smith mc->mc_data = result; 16201ac4b82bSMike Smith mc->mc_length = bufsize; 16211b4404f9SScott Long mc->mc_command = command; 16221ac4b82bSMike Smith 16231ac4b82bSMike Smith if (complete != NULL) { 16241ac4b82bSMike Smith mc->mc_complete = complete; 16251ac4b82bSMike Smith mc->mc_private = mc; 16261b4404f9SScott Long } 16271ac4b82bSMike Smith 16281b4404f9SScott Long error = bus_dmamap_load(sc->mlx_buffer_dmat, mc->mc_dmamap, mc->mc_data, 16291b4404f9SScott Long mc->mc_length, mlx_enquire_cb, mc, BUS_DMA_NOWAIT); 16301b4404f9SScott Long 16311ac4b82bSMike Smith out: 16321ac4b82bSMike Smith /* we got a command, but nobody else will free it */ 163323691262SSam Leffler if ((mc != NULL) && (mc->mc_complete == NULL)) 16341ac4b82bSMike Smith mlx_releasecmd(mc); 163533c8cb18SMike Smith /* we got an error, and we allocated a result */ 1636d4881905SScott Long if ((error != 0) && (result != NULL)) { 1637d4881905SScott Long free(result, M_DEVBUF); 1638a7700303SScott Long result = NULL; 16391ac4b82bSMike Smith } 16401ac4b82bSMike Smith return(result); 16411ac4b82bSMike Smith } 16421ac4b82bSMike Smith 16431ac4b82bSMike Smith 16441ac4b82bSMike Smith /******************************************************************************** 16451ac4b82bSMike Smith * Perform a Flush command on the nominated controller. 16461ac4b82bSMike Smith * 16471ac4b82bSMike Smith * May be called with interrupts enabled or disabled; will not return until 16481ac4b82bSMike Smith * the flush operation completes or fails. 16491ac4b82bSMike Smith */ 16501ac4b82bSMike Smith static int 16511ac4b82bSMike Smith mlx_flush(struct mlx_softc *sc) 16521ac4b82bSMike Smith { 16531ac4b82bSMike Smith struct mlx_command *mc; 16541ac4b82bSMike Smith int error; 16551ac4b82bSMike Smith 1656da8bb3a3SMike Smith debug_called(1); 16570fca6f8bSJohn Baldwin MLX_IO_ASSERT_LOCKED(sc); 16581ac4b82bSMike Smith 16591ac4b82bSMike Smith /* get ourselves a command buffer */ 16601ac4b82bSMike Smith error = 1; 16611ac4b82bSMike Smith if ((mc = mlx_alloccmd(sc)) == NULL) 16621ac4b82bSMike Smith goto out; 16631ac4b82bSMike Smith /* get a command slot */ 16641ac4b82bSMike Smith if (mlx_getslot(mc)) 16651ac4b82bSMike Smith goto out; 16661ac4b82bSMike Smith 16671ac4b82bSMike Smith /* build a flush command */ 16681ac4b82bSMike Smith mlx_make_type2(mc, MLX_CMD_FLUSH, 0, 0, 0, 0, 0, 0, 0, 0); 16691ac4b82bSMike Smith 16705792b7feSMike Smith /* can't assume that interrupts are going to work here, so play it safe */ 16715792b7feSMike Smith if (mlx_poll_command(mc)) 16721ac4b82bSMike Smith goto out; 16731ac4b82bSMike Smith 16741ac4b82bSMike Smith /* command completed OK? */ 16751ac4b82bSMike Smith if (mc->mc_status != 0) { 16761ac4b82bSMike Smith device_printf(sc->mlx_dev, "FLUSH failed - %s\n", mlx_diagnose_command(mc)); 16771ac4b82bSMike Smith goto out; 16781ac4b82bSMike Smith } 16791ac4b82bSMike Smith 16801ac4b82bSMike Smith error = 0; /* success */ 16811ac4b82bSMike Smith out: 16821ac4b82bSMike Smith if (mc != NULL) 16831ac4b82bSMike Smith mlx_releasecmd(mc); 16841ac4b82bSMike Smith return(error); 16851ac4b82bSMike Smith } 16861ac4b82bSMike Smith 16871ac4b82bSMike Smith /******************************************************************************** 1688421f2f7dSMike Smith * Start a background consistency check on (drive). 1689421f2f7dSMike Smith * 1690421f2f7dSMike Smith * May be called with interrupts enabled or disabled; will return as soon as the 1691421f2f7dSMike Smith * operation has started or been refused. 1692421f2f7dSMike Smith */ 1693421f2f7dSMike Smith static int 1694421f2f7dSMike Smith mlx_check(struct mlx_softc *sc, int drive) 1695421f2f7dSMike Smith { 1696421f2f7dSMike Smith struct mlx_command *mc; 1697421f2f7dSMike Smith int error; 1698421f2f7dSMike Smith 1699421f2f7dSMike Smith debug_called(1); 17000fca6f8bSJohn Baldwin MLX_IO_ASSERT_LOCKED(sc); 1701421f2f7dSMike Smith 1702421f2f7dSMike Smith /* get ourselves a command buffer */ 1703421f2f7dSMike Smith error = 0x10000; 1704421f2f7dSMike Smith if ((mc = mlx_alloccmd(sc)) == NULL) 1705421f2f7dSMike Smith goto out; 1706421f2f7dSMike Smith /* get a command slot */ 1707421f2f7dSMike Smith if (mlx_getslot(mc)) 1708421f2f7dSMike Smith goto out; 1709421f2f7dSMike Smith 1710421f2f7dSMike Smith /* build a checkasync command, set the "fix it" flag */ 1711421f2f7dSMike Smith mlx_make_type2(mc, MLX_CMD_CHECKASYNC, 0, 0, 0, 0, 0, drive | 0x80, 0, 0); 1712421f2f7dSMike Smith 1713421f2f7dSMike Smith /* start the command and wait for it to be returned */ 1714421f2f7dSMike Smith if (mlx_wait_command(mc)) 1715421f2f7dSMike Smith goto out; 1716421f2f7dSMike Smith 1717421f2f7dSMike Smith /* command completed OK? */ 1718421f2f7dSMike Smith if (mc->mc_status != 0) { 1719421f2f7dSMike Smith device_printf(sc->mlx_dev, "CHECK ASYNC failed - %s\n", mlx_diagnose_command(mc)); 1720421f2f7dSMike Smith } else { 1721421f2f7dSMike Smith device_printf(sc->mlx_sysdrive[drive].ms_disk, "consistency check started"); 1722421f2f7dSMike Smith } 1723421f2f7dSMike Smith error = mc->mc_status; 1724421f2f7dSMike Smith 1725421f2f7dSMike Smith out: 1726421f2f7dSMike Smith if (mc != NULL) 1727421f2f7dSMike Smith mlx_releasecmd(mc); 1728421f2f7dSMike Smith return(error); 1729421f2f7dSMike Smith } 1730421f2f7dSMike Smith 1731421f2f7dSMike Smith /******************************************************************************** 1732421f2f7dSMike Smith * Start a background rebuild of the physical drive at (channel),(target). 17331ac4b82bSMike Smith * 17341ac4b82bSMike Smith * May be called with interrupts enabled or disabled; will return as soon as the 17351ac4b82bSMike Smith * operation has started or been refused. 17361ac4b82bSMike Smith */ 17371ac4b82bSMike Smith static int 17381ac4b82bSMike Smith mlx_rebuild(struct mlx_softc *sc, int channel, int target) 17391ac4b82bSMike Smith { 17401ac4b82bSMike Smith struct mlx_command *mc; 17411ac4b82bSMike Smith int error; 17421ac4b82bSMike Smith 1743da8bb3a3SMike Smith debug_called(1); 17440fca6f8bSJohn Baldwin MLX_IO_ASSERT_LOCKED(sc); 17451ac4b82bSMike Smith 17461ac4b82bSMike Smith /* get ourselves a command buffer */ 17471ac4b82bSMike Smith error = 0x10000; 17481ac4b82bSMike Smith if ((mc = mlx_alloccmd(sc)) == NULL) 17491ac4b82bSMike Smith goto out; 17501ac4b82bSMike Smith /* get a command slot */ 17511ac4b82bSMike Smith if (mlx_getslot(mc)) 17521ac4b82bSMike Smith goto out; 17531ac4b82bSMike Smith 1754421f2f7dSMike Smith /* build a checkasync command, set the "fix it" flag */ 17551ac4b82bSMike Smith mlx_make_type2(mc, MLX_CMD_REBUILDASYNC, channel, target, 0, 0, 0, 0, 0, 0); 17561ac4b82bSMike Smith 1757421f2f7dSMike Smith /* start the command and wait for it to be returned */ 1758421f2f7dSMike Smith if (mlx_wait_command(mc)) 17591ac4b82bSMike Smith goto out; 17601ac4b82bSMike Smith 17611ac4b82bSMike Smith /* command completed OK? */ 17621ac4b82bSMike Smith if (mc->mc_status != 0) { 17631ac4b82bSMike Smith device_printf(sc->mlx_dev, "REBUILD ASYNC failed - %s\n", mlx_diagnose_command(mc)); 17641ac4b82bSMike Smith } else { 1765421f2f7dSMike Smith device_printf(sc->mlx_dev, "drive rebuild started for %d:%d\n", channel, target); 17661ac4b82bSMike Smith } 17671ac4b82bSMike Smith error = mc->mc_status; 17681ac4b82bSMike Smith 17691ac4b82bSMike Smith out: 17701ac4b82bSMike Smith if (mc != NULL) 17711ac4b82bSMike Smith mlx_releasecmd(mc); 17721ac4b82bSMike Smith return(error); 17731ac4b82bSMike Smith } 17741ac4b82bSMike Smith 17751ac4b82bSMike Smith /******************************************************************************** 17761ac4b82bSMike Smith * Run the command (mc) and return when it completes. 17771ac4b82bSMike Smith * 17781ac4b82bSMike Smith * Interrupts need to be enabled; returns nonzero on error. 17791ac4b82bSMike Smith */ 17801ac4b82bSMike Smith static int 17811ac4b82bSMike Smith mlx_wait_command(struct mlx_command *mc) 17821ac4b82bSMike Smith { 17831ac4b82bSMike Smith struct mlx_softc *sc = mc->mc_sc; 17841ac4b82bSMike Smith int error, count; 17851ac4b82bSMike Smith 1786da8bb3a3SMike Smith debug_called(1); 17870fca6f8bSJohn Baldwin MLX_IO_ASSERT_LOCKED(sc); 17881ac4b82bSMike Smith 17891ac4b82bSMike Smith mc->mc_complete = NULL; 17901ac4b82bSMike Smith mc->mc_private = mc; /* wake us when you're done */ 17911ac4b82bSMike Smith if ((error = mlx_start(mc)) != 0) 17921ac4b82bSMike Smith return(error); 17931ac4b82bSMike Smith 17941ac4b82bSMike Smith count = 0; 17951ac4b82bSMike Smith /* XXX better timeout? */ 17961ac4b82bSMike Smith while ((mc->mc_status == MLX_STATUS_BUSY) && (count < 30)) { 17970fca6f8bSJohn Baldwin mtx_sleep(mc->mc_private, &sc->mlx_io_lock, PRIBIO | PCATCH, "mlxwcmd", hz); 17981ac4b82bSMike Smith } 17991ac4b82bSMike Smith 18001ac4b82bSMike Smith if (mc->mc_status != 0) { 1801da8bb3a3SMike Smith device_printf(sc->mlx_dev, "command failed - %s\n", mlx_diagnose_command(mc)); 18021ac4b82bSMike Smith return(EIO); 18031ac4b82bSMike Smith } 18041ac4b82bSMike Smith return(0); 18051ac4b82bSMike Smith } 18061ac4b82bSMike Smith 18071ac4b82bSMike Smith 18081ac4b82bSMike Smith /******************************************************************************** 18091ac4b82bSMike Smith * Start the command (mc) and busy-wait for it to complete. 18101ac4b82bSMike Smith * 1811da8bb3a3SMike Smith * Should only be used when interrupts can't be relied upon. Returns 0 on 18121ac4b82bSMike Smith * success, nonzero on error. 18131ac4b82bSMike Smith * Successfully completed commands are dequeued. 18141ac4b82bSMike Smith */ 18151ac4b82bSMike Smith static int 18161ac4b82bSMike Smith mlx_poll_command(struct mlx_command *mc) 18171ac4b82bSMike Smith { 18181ac4b82bSMike Smith struct mlx_softc *sc = mc->mc_sc; 18190fca6f8bSJohn Baldwin int error, count; 18201ac4b82bSMike Smith 1821da8bb3a3SMike Smith debug_called(1); 18220fca6f8bSJohn Baldwin MLX_IO_ASSERT_LOCKED(sc); 18231ac4b82bSMike Smith 18241ac4b82bSMike Smith mc->mc_complete = NULL; 18251ac4b82bSMike Smith mc->mc_private = NULL; /* we will poll for it */ 18261ac4b82bSMike Smith if ((error = mlx_start(mc)) != 0) 18271ac4b82bSMike Smith return(error); 18281ac4b82bSMike Smith 18291ac4b82bSMike Smith count = 0; 18301ac4b82bSMike Smith do { 18311ac4b82bSMike Smith /* poll for completion */ 18320fca6f8bSJohn Baldwin mlx_done(mc->mc_sc, 1); 1833da8bb3a3SMike Smith 1834da8bb3a3SMike Smith } while ((mc->mc_status == MLX_STATUS_BUSY) && (count++ < 15000000)); 18351ac4b82bSMike Smith if (mc->mc_status != MLX_STATUS_BUSY) { 18364b006d7bSMike Smith TAILQ_REMOVE(&sc->mlx_work, mc, mc_link); 18371ac4b82bSMike Smith return(0); 18381ac4b82bSMike Smith } 1839421f2f7dSMike Smith device_printf(sc->mlx_dev, "command failed - %s\n", mlx_diagnose_command(mc)); 18401ac4b82bSMike Smith return(EIO); 18411ac4b82bSMike Smith } 18421ac4b82bSMike Smith 18431b4404f9SScott Long void 18441b4404f9SScott Long mlx_startio_cb(void *arg, bus_dma_segment_t *segs, int nsegments, int error) 18451b4404f9SScott Long { 18461b4404f9SScott Long struct mlx_command *mc; 18471b4404f9SScott Long struct mlxd_softc *mlxd; 18481b4404f9SScott Long struct mlx_softc *sc; 1849b04e4c12SJohn Baldwin struct bio *bp; 18501b4404f9SScott Long int blkcount; 18511b4404f9SScott Long int driveno; 18521b4404f9SScott Long int cmd; 18531b4404f9SScott Long 18541b4404f9SScott Long mc = (struct mlx_command *)arg; 18551b4404f9SScott Long mlx_setup_dmamap(mc, segs, nsegments, error); 18561b4404f9SScott Long 18571b4404f9SScott Long sc = mc->mc_sc; 18581b4404f9SScott Long bp = mc->mc_private; 18591b4404f9SScott Long 1860b04e4c12SJohn Baldwin if (bp->bio_cmd == BIO_READ) { 18611b4404f9SScott Long mc->mc_flags |= MLX_CMD_DATAIN; 18621b4404f9SScott Long cmd = MLX_CMD_READSG; 18631b4404f9SScott Long } else { 18641b4404f9SScott Long mc->mc_flags |= MLX_CMD_DATAOUT; 18651b4404f9SScott Long cmd = MLX_CMD_WRITESG; 18661b4404f9SScott Long } 18671b4404f9SScott Long 18681b4404f9SScott Long /* build a suitable I/O command (assumes 512-byte rounded transfers) */ 1869b04e4c12SJohn Baldwin mlxd = bp->bio_disk->d_drv1; 18701b4404f9SScott Long driveno = mlxd->mlxd_drive - sc->mlx_sysdrive; 1871b04e4c12SJohn Baldwin blkcount = (bp->bio_bcount + MLX_BLKSIZE - 1) / MLX_BLKSIZE; 18721b4404f9SScott Long 1873b04e4c12SJohn Baldwin if ((bp->bio_pblkno + blkcount) > sc->mlx_sysdrive[driveno].ms_size) 18741b4404f9SScott Long device_printf(sc->mlx_dev, 18751b4404f9SScott Long "I/O beyond end of unit (%lld,%d > %lu)\n", 1876b04e4c12SJohn Baldwin (long long)bp->bio_pblkno, blkcount, 18771b4404f9SScott Long (u_long)sc->mlx_sysdrive[driveno].ms_size); 18781b4404f9SScott Long 18791b4404f9SScott Long /* 18801b4404f9SScott Long * Build the I/O command. Note that the SG list type bits are set to zero, 18811b4404f9SScott Long * denoting the format of SG list that we are using. 18821b4404f9SScott Long */ 18831b4404f9SScott Long if (sc->mlx_iftype == MLX_IFTYPE_2) { 18841b4404f9SScott Long mlx_make_type1(mc, (cmd == MLX_CMD_WRITESG) ? MLX_CMD_WRITESG_OLD : 18851b4404f9SScott Long MLX_CMD_READSG_OLD, 18861b4404f9SScott Long blkcount & 0xff, /* xfer length low byte */ 1887b04e4c12SJohn Baldwin bp->bio_pblkno, /* physical block number */ 18881b4404f9SScott Long driveno, /* target drive number */ 18891b4404f9SScott Long mc->mc_sgphys, /* location of SG list */ 18901b4404f9SScott Long mc->mc_nsgent & 0x3f); /* size of SG list */ 18911b4404f9SScott Long } else { 18921b4404f9SScott Long mlx_make_type5(mc, cmd, 18931b4404f9SScott Long blkcount & 0xff, /* xfer length low byte */ 18941b4404f9SScott Long (driveno << 3) | ((blkcount >> 8) & 0x07), 18951b4404f9SScott Long /* target+length high 3 bits */ 1896b04e4c12SJohn Baldwin bp->bio_pblkno, /* physical block number */ 18971b4404f9SScott Long mc->mc_sgphys, /* location of SG list */ 18981b4404f9SScott Long mc->mc_nsgent & 0x3f); /* size of SG list */ 18991b4404f9SScott Long } 19001b4404f9SScott Long 19011b4404f9SScott Long /* try to give command to controller */ 19021b4404f9SScott Long if (mlx_start(mc) != 0) { 19031b4404f9SScott Long /* fail the command */ 19041b4404f9SScott Long mc->mc_status = MLX_STATUS_WEDGED; 19051b4404f9SScott Long mlx_completeio(mc); 19061b4404f9SScott Long } 19070fca6f8bSJohn Baldwin 19080fca6f8bSJohn Baldwin sc->mlx_state &= ~MLX_STATE_QFROZEN; 19091b4404f9SScott Long } 19101b4404f9SScott Long 19111ac4b82bSMike Smith /******************************************************************************** 19121ac4b82bSMike Smith * Pull as much work off the softc's work queue as possible and give it to the 19131ac4b82bSMike Smith * controller. Leave a couple of slots free for emergencies. 19141ac4b82bSMike Smith */ 19151ac4b82bSMike Smith static void 19161ac4b82bSMike Smith mlx_startio(struct mlx_softc *sc) 19171ac4b82bSMike Smith { 19181ac4b82bSMike Smith struct mlx_command *mc; 1919b04e4c12SJohn Baldwin struct bio *bp; 19201b4404f9SScott Long int error; 19211ac4b82bSMike Smith 19220fca6f8bSJohn Baldwin MLX_IO_ASSERT_LOCKED(sc); 19235792b7feSMike Smith 19241ac4b82bSMike Smith /* spin until something prevents us from doing any work */ 19251ac4b82bSMike Smith for (;;) { 19260fca6f8bSJohn Baldwin if (sc->mlx_state & MLX_STATE_QFROZEN) 19270fca6f8bSJohn Baldwin break; 19281ac4b82bSMike Smith 19291ac4b82bSMike Smith /* see if there's work to be done */ 1930b04e4c12SJohn Baldwin if ((bp = bioq_first(&sc->mlx_bioq)) == NULL) 19311ac4b82bSMike Smith break; 19321ac4b82bSMike Smith /* get a command */ 19331ac4b82bSMike Smith if ((mc = mlx_alloccmd(sc)) == NULL) 19341ac4b82bSMike Smith break; 19351ac4b82bSMike Smith /* get a slot for the command */ 19361ac4b82bSMike Smith if (mlx_getslot(mc) != 0) { 19371ac4b82bSMike Smith mlx_releasecmd(mc); 19381ac4b82bSMike Smith break; 19391ac4b82bSMike Smith } 19401ac4b82bSMike Smith /* get the buf containing our work */ 1941b04e4c12SJohn Baldwin bioq_remove(&sc->mlx_bioq, bp); 19421ac4b82bSMike Smith sc->mlx_waitbufs--; 19431ac4b82bSMike Smith 19441ac4b82bSMike Smith /* connect the buf to the command */ 19451ac4b82bSMike Smith mc->mc_complete = mlx_completeio; 19461ac4b82bSMike Smith mc->mc_private = bp; 1947b04e4c12SJohn Baldwin mc->mc_data = bp->bio_data; 1948b04e4c12SJohn Baldwin mc->mc_length = bp->bio_bcount; 19491ac4b82bSMike Smith 19501ac4b82bSMike Smith /* map the command so the controller can work with it */ 19511b4404f9SScott Long error = bus_dmamap_load(sc->mlx_buffer_dmat, mc->mc_dmamap, mc->mc_data, 19521b4404f9SScott Long mc->mc_length, mlx_startio_cb, mc, 0); 19531b4404f9SScott Long if (error == EINPROGRESS) { 19540fca6f8bSJohn Baldwin sc->mlx_state |= MLX_STATE_QFROZEN; 19551b4404f9SScott Long break; 1956da8bb3a3SMike Smith } 19571ac4b82bSMike Smith } 19581ac4b82bSMike Smith } 19591ac4b82bSMike Smith 19601ac4b82bSMike Smith /******************************************************************************** 19611ac4b82bSMike Smith * Handle completion of an I/O command. 19621ac4b82bSMike Smith */ 19631ac4b82bSMike Smith static void 19641ac4b82bSMike Smith mlx_completeio(struct mlx_command *mc) 19651ac4b82bSMike Smith { 19661ac4b82bSMike Smith struct mlx_softc *sc = mc->mc_sc; 1967b04e4c12SJohn Baldwin struct bio *bp = mc->mc_private; 1968b04e4c12SJohn Baldwin struct mlxd_softc *mlxd = bp->bio_disk->d_drv1; 19691ac4b82bSMike Smith 19700fca6f8bSJohn Baldwin MLX_IO_ASSERT_LOCKED(sc); 19711ac4b82bSMike Smith if (mc->mc_status != MLX_STATUS_OK) { /* could be more verbose here? */ 1972b04e4c12SJohn Baldwin bp->bio_error = EIO; 1973b04e4c12SJohn Baldwin bp->bio_flags |= BIO_ERROR; 19741ac4b82bSMike Smith 19751ac4b82bSMike Smith switch(mc->mc_status) { 19761ac4b82bSMike Smith case MLX_STATUS_RDWROFFLINE: /* system drive has gone offline */ 19771ac4b82bSMike Smith device_printf(mlxd->mlxd_dev, "drive offline\n"); 1978f6b84b08SMike Smith /* should signal this with a return code */ 19791ac4b82bSMike Smith mlxd->mlxd_drive->ms_state = MLX_SYSD_OFFLINE; 19801ac4b82bSMike Smith break; 19811ac4b82bSMike Smith 19821ac4b82bSMike Smith default: /* other I/O error */ 19831ac4b82bSMike Smith device_printf(sc->mlx_dev, "I/O error - %s\n", mlx_diagnose_command(mc)); 19841ac4b82bSMike Smith #if 0 1985cd4ace0cSMike Smith device_printf(sc->mlx_dev, " b_bcount %ld blkcount %ld b_pblkno %d\n", 1986b04e4c12SJohn Baldwin bp->bio_bcount, bp->bio_bcount / MLX_BLKSIZE, bp->bio_pblkno); 19871ac4b82bSMike Smith device_printf(sc->mlx_dev, " %13D\n", mc->mc_mailbox, " "); 19881ac4b82bSMike Smith #endif 19891ac4b82bSMike Smith break; 19901ac4b82bSMike Smith } 19911ac4b82bSMike Smith } 19921ac4b82bSMike Smith mlx_releasecmd(mc); 19931ac4b82bSMike Smith mlxd_intr(bp); 19941ac4b82bSMike Smith } 19951ac4b82bSMike Smith 19961b4404f9SScott Long void 19971b4404f9SScott Long mlx_user_cb(void *arg, bus_dma_segment_t *segs, int nsegments, int error) 19981b4404f9SScott Long { 19991b4404f9SScott Long struct mlx_usercommand *mu; 20001b4404f9SScott Long struct mlx_command *mc; 20011b4404f9SScott Long struct mlx_dcdb *dcdb; 20021b4404f9SScott Long 20031b4404f9SScott Long mc = (struct mlx_command *)arg; 20041b4404f9SScott Long if (error) 20051b4404f9SScott Long return; 20061b4404f9SScott Long 20071b4404f9SScott Long mlx_setup_dmamap(mc, segs, nsegments, error); 20081b4404f9SScott Long 20091b4404f9SScott Long mu = (struct mlx_usercommand *)mc->mc_private; 20101b4404f9SScott Long dcdb = NULL; 20111b4404f9SScott Long 20121b4404f9SScott Long /* 20131b4404f9SScott Long * If this is a passthrough SCSI command, the DCDB is packed at the 20141b4404f9SScott Long * beginning of the data area. Fix up the DCDB to point to the correct 20151b4404f9SScott Long * physical address and override any bufptr supplied by the caller since 20161b4404f9SScott Long * we know what it's meant to be. 20171b4404f9SScott Long */ 20181b4404f9SScott Long if (mc->mc_mailbox[0] == MLX_CMD_DIRECT_CDB) { 20191b4404f9SScott Long dcdb = (struct mlx_dcdb *)mc->mc_data; 20201b4404f9SScott Long dcdb->dcdb_physaddr = mc->mc_dataphys + sizeof(*dcdb); 20211b4404f9SScott Long mu->mu_bufptr = 8; 20221b4404f9SScott Long } 20231b4404f9SScott Long 20241b4404f9SScott Long /* 20251b4404f9SScott Long * If there's a data buffer, fix up the command's buffer pointer. 20261b4404f9SScott Long */ 20271b4404f9SScott Long if (mu->mu_datasize > 0) { 20281b4404f9SScott Long mc->mc_mailbox[mu->mu_bufptr ] = mc->mc_dataphys & 0xff; 20291b4404f9SScott Long mc->mc_mailbox[mu->mu_bufptr + 1] = (mc->mc_dataphys >> 8) & 0xff; 20301b4404f9SScott Long mc->mc_mailbox[mu->mu_bufptr + 2] = (mc->mc_dataphys >> 16) & 0xff; 20311b4404f9SScott Long mc->mc_mailbox[mu->mu_bufptr + 3] = (mc->mc_dataphys >> 24) & 0xff; 20321b4404f9SScott Long } 20331b4404f9SScott Long debug(0, "command fixup"); 20341b4404f9SScott Long 20351b4404f9SScott Long /* submit the command and wait */ 20361b4404f9SScott Long if (mlx_wait_command(mc) != 0) 20371b4404f9SScott Long return; 20381b4404f9SScott Long 20391b4404f9SScott Long } 20401b4404f9SScott Long 20411ac4b82bSMike Smith /******************************************************************************** 20421ac4b82bSMike Smith * Take a command from user-space and try to run it. 2043da8bb3a3SMike Smith * 2044da8bb3a3SMike Smith * XXX Note that this can't perform very much in the way of error checking, and 2045da8bb3a3SMike Smith * as such, applications _must_ be considered trustworthy. 2046da8bb3a3SMike Smith * XXX Commands using S/G for data are not supported. 20471ac4b82bSMike Smith */ 20481ac4b82bSMike Smith static int 20491ac4b82bSMike Smith mlx_user_command(struct mlx_softc *sc, struct mlx_usercommand *mu) 20501ac4b82bSMike Smith { 20511ac4b82bSMike Smith struct mlx_command *mc; 20521ac4b82bSMike Smith void *kbuf; 20531ac4b82bSMike Smith int error; 20541ac4b82bSMike Smith 2055da8bb3a3SMike Smith debug_called(0); 2056da8bb3a3SMike Smith 20571ac4b82bSMike Smith kbuf = NULL; 20581ac4b82bSMike Smith mc = NULL; 20591ac4b82bSMike Smith error = ENOMEM; 2060da8bb3a3SMike Smith 2061da8bb3a3SMike Smith /* get ourselves a command and copy in from user space */ 20620fca6f8bSJohn Baldwin MLX_IO_LOCK(sc); 20630fca6f8bSJohn Baldwin if ((mc = mlx_alloccmd(sc)) == NULL) { 20640fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc); 2065001ea8fbSSam Leffler return(error); 20660fca6f8bSJohn Baldwin } 20671ac4b82bSMike Smith bcopy(mu->mu_command, mc->mc_mailbox, sizeof(mc->mc_mailbox)); 2068da8bb3a3SMike Smith debug(0, "got command buffer"); 2069da8bb3a3SMike Smith 20701b4404f9SScott Long /* 20711b4404f9SScott Long * if we need a buffer for data transfer, allocate one and copy in its 20721b4404f9SScott Long * initial contents 20731b4404f9SScott Long */ 2074da8bb3a3SMike Smith if (mu->mu_datasize > 0) { 207552c9ce25SScott Long if (mu->mu_datasize > MLX_MAXPHYS) { 2076aa083c3dSSam Leffler error = EINVAL; 2077aa083c3dSSam Leffler goto out; 2078aa083c3dSSam Leffler } 20790fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc); 2080a163d034SWarner Losh if (((kbuf = malloc(mu->mu_datasize, M_DEVBUF, M_WAITOK)) == NULL) || 20810fca6f8bSJohn Baldwin (error = copyin(mu->mu_buf, kbuf, mu->mu_datasize))) { 20820fca6f8bSJohn Baldwin MLX_IO_LOCK(sc); 20831ac4b82bSMike Smith goto out; 20840fca6f8bSJohn Baldwin } 20850fca6f8bSJohn Baldwin MLX_IO_LOCK(sc); 2086da8bb3a3SMike Smith debug(0, "got kernel buffer"); 2087da8bb3a3SMike Smith } 20881ac4b82bSMike Smith 20891ac4b82bSMike Smith /* get a command slot */ 20901ac4b82bSMike Smith if (mlx_getslot(mc)) 20911ac4b82bSMike Smith goto out; 2092da8bb3a3SMike Smith debug(0, "got a slot"); 20931ac4b82bSMike Smith 2094da8bb3a3SMike Smith if (mu->mu_datasize > 0) { 2095da8bb3a3SMike Smith 2096da8bb3a3SMike Smith /* range check the pointer to physical buffer address */ 20971b4404f9SScott Long if ((mu->mu_bufptr < 0) || (mu->mu_bufptr > (sizeof(mu->mu_command) - 20981b4404f9SScott Long sizeof(u_int32_t)))) { 2099da8bb3a3SMike Smith error = EINVAL; 2100da8bb3a3SMike Smith goto out; 2101da8bb3a3SMike Smith } 2102da8bb3a3SMike Smith } 2103da8bb3a3SMike Smith 21041b4404f9SScott Long /* map the command so the controller can see it */ 21051b4404f9SScott Long mc->mc_data = kbuf; 21061b4404f9SScott Long mc->mc_length = mu->mu_datasize; 21071b4404f9SScott Long mc->mc_private = mu; 21081b4404f9SScott Long error = bus_dmamap_load(sc->mlx_buffer_dmat, mc->mc_dmamap, mc->mc_data, 21091b4404f9SScott Long mc->mc_length, mlx_user_cb, mc, BUS_DMA_NOWAIT); 21100fca6f8bSJohn Baldwin if (error) 21110fca6f8bSJohn Baldwin goto out; 21121ac4b82bSMike Smith 21131ac4b82bSMike Smith /* copy out status and data */ 21141ac4b82bSMike Smith mu->mu_status = mc->mc_status; 21150fca6f8bSJohn Baldwin if (mu->mu_datasize > 0) { 21160fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc); 21170fca6f8bSJohn Baldwin error = copyout(kbuf, mu->mu_buf, mu->mu_datasize); 21180fca6f8bSJohn Baldwin MLX_IO_LOCK(sc); 21190fca6f8bSJohn Baldwin } 21201ac4b82bSMike Smith 21211ac4b82bSMike Smith out: 21221ac4b82bSMike Smith mlx_releasecmd(mc); 21230fca6f8bSJohn Baldwin MLX_IO_UNLOCK(sc); 21241ac4b82bSMike Smith if (kbuf != NULL) 21251ac4b82bSMike Smith free(kbuf, M_DEVBUF); 21261ac4b82bSMike Smith return(error); 21271ac4b82bSMike Smith } 21281ac4b82bSMike Smith 21291ac4b82bSMike Smith /******************************************************************************** 21301ac4b82bSMike Smith ******************************************************************************** 21311ac4b82bSMike Smith Command I/O to Controller 21321ac4b82bSMike Smith ******************************************************************************** 21331ac4b82bSMike Smith ********************************************************************************/ 21341ac4b82bSMike Smith 21351ac4b82bSMike Smith /******************************************************************************** 21361ac4b82bSMike Smith * Find a free command slot for (mc). 21371ac4b82bSMike Smith * 21381ac4b82bSMike Smith * Don't hand out a slot to a normal-priority command unless there are at least 21391ac4b82bSMike Smith * 4 slots free for priority commands. 21401ac4b82bSMike Smith */ 21411ac4b82bSMike Smith static int 21421ac4b82bSMike Smith mlx_getslot(struct mlx_command *mc) 21431ac4b82bSMike Smith { 21441ac4b82bSMike Smith struct mlx_softc *sc = mc->mc_sc; 21450fca6f8bSJohn Baldwin int slot, limit; 21461ac4b82bSMike Smith 2147da8bb3a3SMike Smith debug_called(1); 21481ac4b82bSMike Smith 21490fca6f8bSJohn Baldwin MLX_IO_ASSERT_LOCKED(sc); 21500fca6f8bSJohn Baldwin 2151baff09dbSMike Smith /* 2152baff09dbSMike Smith * Enforce slot-usage limit, if we have the required information. 2153baff09dbSMike Smith */ 2154baff09dbSMike Smith if (sc->mlx_enq2 != NULL) { 2155baff09dbSMike Smith limit = sc->mlx_enq2->me_max_commands; 2156baff09dbSMike Smith } else { 2157baff09dbSMike Smith limit = 2; 2158baff09dbSMike Smith } 2159baff09dbSMike Smith if (sc->mlx_busycmds >= ((mc->mc_flags & MLX_CMD_PRIORITY) ? limit : limit - 4)) 21601ac4b82bSMike Smith return(EBUSY); 21611ac4b82bSMike Smith 21621ac4b82bSMike Smith /* 21631ac4b82bSMike Smith * Allocate an outstanding command slot 21641ac4b82bSMike Smith * 21651ac4b82bSMike Smith * XXX linear search is slow 21661ac4b82bSMike Smith */ 2167baff09dbSMike Smith for (slot = 0; slot < limit; slot++) { 2168da8bb3a3SMike Smith debug(2, "try slot %d", slot); 21691ac4b82bSMike Smith if (sc->mlx_busycmd[slot] == NULL) 21701ac4b82bSMike Smith break; 21711ac4b82bSMike Smith } 2172baff09dbSMike Smith if (slot < limit) { 21731ac4b82bSMike Smith sc->mlx_busycmd[slot] = mc; 21741ac4b82bSMike Smith sc->mlx_busycmds++; 21751ac4b82bSMike Smith } 21761ac4b82bSMike Smith 21771ac4b82bSMike Smith /* out of slots? */ 2178baff09dbSMike Smith if (slot >= limit) 21791ac4b82bSMike Smith return(EBUSY); 21801ac4b82bSMike Smith 2181da8bb3a3SMike Smith debug(2, "got slot %d", slot); 21821ac4b82bSMike Smith mc->mc_slot = slot; 21831ac4b82bSMike Smith return(0); 21841ac4b82bSMike Smith } 21851ac4b82bSMike Smith 21861ac4b82bSMike Smith /******************************************************************************** 21871ac4b82bSMike Smith * Map/unmap (mc)'s data in the controller's addressable space. 21881ac4b82bSMike Smith */ 21891ac4b82bSMike Smith static void 21901b4404f9SScott Long mlx_setup_dmamap(struct mlx_command *mc, bus_dma_segment_t *segs, int nsegments, 21911b4404f9SScott Long int error) 21921ac4b82bSMike Smith { 21931ac4b82bSMike Smith struct mlx_softc *sc = mc->mc_sc; 21941ac4b82bSMike Smith struct mlx_sgentry *sg; 21951ac4b82bSMike Smith int i; 21961ac4b82bSMike Smith 2197da8bb3a3SMike Smith debug_called(1); 21981ac4b82bSMike Smith 2199baff09dbSMike Smith /* XXX should be unnecessary */ 2200baff09dbSMike Smith if (sc->mlx_enq2 && (nsegments > sc->mlx_enq2->me_max_sg)) 22011b4404f9SScott Long panic("MLX: too many s/g segments (%d, max %d)", nsegments, 22021b4404f9SScott Long sc->mlx_enq2->me_max_sg); 2203baff09dbSMike Smith 22041ac4b82bSMike Smith /* get base address of s/g table */ 2205baff09dbSMike Smith sg = sc->mlx_sgtable + (mc->mc_slot * MLX_NSEG); 22061ac4b82bSMike Smith 22071ac4b82bSMike Smith /* save s/g table information in command */ 22081ac4b82bSMike Smith mc->mc_nsgent = nsegments; 22091b4404f9SScott Long mc->mc_sgphys = sc->mlx_sgbusaddr + 22101b4404f9SScott Long (mc->mc_slot * MLX_NSEG * sizeof(struct mlx_sgentry)); 22111ac4b82bSMike Smith mc->mc_dataphys = segs[0].ds_addr; 22121ac4b82bSMike Smith 22131ac4b82bSMike Smith /* populate s/g table */ 22141ac4b82bSMike Smith for (i = 0; i < nsegments; i++, sg++) { 22151ac4b82bSMike Smith sg->sg_addr = segs[i].ds_addr; 22161ac4b82bSMike Smith sg->sg_count = segs[i].ds_len; 22171ac4b82bSMike Smith } 22181ac4b82bSMike Smith 22191b4404f9SScott Long /* Make sure the buffers are visible on the bus. */ 22201ac4b82bSMike Smith if (mc->mc_flags & MLX_CMD_DATAIN) 22211b4404f9SScott Long bus_dmamap_sync(sc->mlx_buffer_dmat, mc->mc_dmamap, 22221b4404f9SScott Long BUS_DMASYNC_PREREAD); 22231ac4b82bSMike Smith if (mc->mc_flags & MLX_CMD_DATAOUT) 22241b4404f9SScott Long bus_dmamap_sync(sc->mlx_buffer_dmat, mc->mc_dmamap, 22251b4404f9SScott Long BUS_DMASYNC_PREWRITE); 22261ac4b82bSMike Smith } 22271ac4b82bSMike Smith 22281ac4b82bSMike Smith static void 22291ac4b82bSMike Smith mlx_unmapcmd(struct mlx_command *mc) 22301ac4b82bSMike Smith { 22311ac4b82bSMike Smith struct mlx_softc *sc = mc->mc_sc; 22321ac4b82bSMike Smith 2233da8bb3a3SMike Smith debug_called(1); 22341ac4b82bSMike Smith 22351ac4b82bSMike Smith /* if the command involved data at all */ 22361ac4b82bSMike Smith if (mc->mc_data != NULL) { 22371ac4b82bSMike Smith 22381ac4b82bSMike Smith if (mc->mc_flags & MLX_CMD_DATAIN) 22391ac4b82bSMike Smith bus_dmamap_sync(sc->mlx_buffer_dmat, mc->mc_dmamap, BUS_DMASYNC_POSTREAD); 22401ac4b82bSMike Smith if (mc->mc_flags & MLX_CMD_DATAOUT) 22411ac4b82bSMike Smith bus_dmamap_sync(sc->mlx_buffer_dmat, mc->mc_dmamap, BUS_DMASYNC_POSTWRITE); 22421ac4b82bSMike Smith 22431ac4b82bSMike Smith bus_dmamap_unload(sc->mlx_buffer_dmat, mc->mc_dmamap); 22441ac4b82bSMike Smith } 22451ac4b82bSMike Smith } 22461ac4b82bSMike Smith 22471ac4b82bSMike Smith /******************************************************************************** 22485792b7feSMike Smith * Try to deliver (mc) to the controller. 22491ac4b82bSMike Smith * 22501ac4b82bSMike Smith * Can be called at any interrupt level, with or without interrupts enabled. 22511ac4b82bSMike Smith */ 22521ac4b82bSMike Smith static int 22531ac4b82bSMike Smith mlx_start(struct mlx_command *mc) 22541ac4b82bSMike Smith { 22551ac4b82bSMike Smith struct mlx_softc *sc = mc->mc_sc; 22560fca6f8bSJohn Baldwin int i; 22571ac4b82bSMike Smith 2258da8bb3a3SMike Smith debug_called(1); 22591ac4b82bSMike Smith 22601ac4b82bSMike Smith /* save the slot number as ident so we can handle this command when complete */ 22611ac4b82bSMike Smith mc->mc_mailbox[0x1] = mc->mc_slot; 22621ac4b82bSMike Smith 22634b006d7bSMike Smith /* mark the command as currently being processed */ 22641ac4b82bSMike Smith mc->mc_status = MLX_STATUS_BUSY; 22651ac4b82bSMike Smith 22665792b7feSMike Smith /* set a default 60-second timeout XXX tunable? XXX not currently used */ 22675792b7feSMike Smith mc->mc_timeout = time_second + 60; 22681ac4b82bSMike Smith 22691ac4b82bSMike Smith /* spin waiting for the mailbox */ 22700fca6f8bSJohn Baldwin for (i = 100000; i > 0; i--) { 22714b006d7bSMike Smith if (sc->mlx_tryqueue(sc, mc)) { 22724b006d7bSMike Smith /* move command to work queue */ 22734b006d7bSMike Smith TAILQ_INSERT_TAIL(&sc->mlx_work, mc, mc_link); 22741ac4b82bSMike Smith return (0); 22750fca6f8bSJohn Baldwin } else if (i > 1) 22760fca6f8bSJohn Baldwin mlx_done(sc, 0); 22770fca6f8bSJohn Baldwin } 22781ac4b82bSMike Smith 22791ac4b82bSMike Smith /* 22801ac4b82bSMike Smith * We couldn't get the controller to take the command. Revoke the slot 22811ac4b82bSMike Smith * that the command was given and return it with a bad status. 22821ac4b82bSMike Smith */ 22831ac4b82bSMike Smith sc->mlx_busycmd[mc->mc_slot] = NULL; 22841ac4b82bSMike Smith device_printf(sc->mlx_dev, "controller wedged (not taking commands)\n"); 22851ac4b82bSMike Smith mc->mc_status = MLX_STATUS_WEDGED; 22865792b7feSMike Smith mlx_complete(sc); 22871ac4b82bSMike Smith return(EIO); 22881ac4b82bSMike Smith } 22891ac4b82bSMike Smith 22901ac4b82bSMike Smith /******************************************************************************** 22915792b7feSMike Smith * Poll the controller (sc) for completed commands. 22925792b7feSMike Smith * Update command status and free slots for reuse. If any slots were freed, 22935792b7feSMike Smith * new commands may be posted. 22941ac4b82bSMike Smith * 22955792b7feSMike Smith * Returns nonzero if one or more commands were completed. 22961ac4b82bSMike Smith */ 22971ac4b82bSMike Smith static int 22980fca6f8bSJohn Baldwin mlx_done(struct mlx_softc *sc, int startio) 22991ac4b82bSMike Smith { 23001ac4b82bSMike Smith struct mlx_command *mc; 23010fca6f8bSJohn Baldwin int result; 23021ac4b82bSMike Smith u_int8_t slot; 23031ac4b82bSMike Smith u_int16_t status; 23041ac4b82bSMike Smith 2305da8bb3a3SMike Smith debug_called(2); 23060fca6f8bSJohn Baldwin MLX_IO_ASSERT_LOCKED(sc); 23071ac4b82bSMike Smith 23085792b7feSMike Smith result = 0; 23091ac4b82bSMike Smith 23105792b7feSMike Smith /* loop collecting completed commands */ 23115792b7feSMike Smith for (;;) { 23125792b7feSMike Smith /* poll for a completed command's identifier and status */ 23131ac4b82bSMike Smith if (sc->mlx_findcomplete(sc, &slot, &status)) { 23145792b7feSMike Smith result = 1; 23151ac4b82bSMike Smith mc = sc->mlx_busycmd[slot]; /* find command */ 23161ac4b82bSMike Smith if (mc != NULL) { /* paranoia */ 23171ac4b82bSMike Smith if (mc->mc_status == MLX_STATUS_BUSY) { 23181ac4b82bSMike Smith mc->mc_status = status; /* save status */ 23191ac4b82bSMike Smith 23201ac4b82bSMike Smith /* free slot for reuse */ 23211ac4b82bSMike Smith sc->mlx_busycmd[slot] = NULL; 23221ac4b82bSMike Smith sc->mlx_busycmds--; 23231ac4b82bSMike Smith } else { 23241ac4b82bSMike Smith device_printf(sc->mlx_dev, "duplicate done event for slot %d\n", slot); 23251ac4b82bSMike Smith } 23261ac4b82bSMike Smith } else { 23271ac4b82bSMike Smith device_printf(sc->mlx_dev, "done event for nonbusy slot %d\n", slot); 23281ac4b82bSMike Smith } 23295792b7feSMike Smith } else { 23305792b7feSMike Smith break; 23311ac4b82bSMike Smith } 23325792b7feSMike Smith } 23331ac4b82bSMike Smith 23345792b7feSMike Smith /* if we've completed any commands, try posting some more */ 23350fca6f8bSJohn Baldwin if (result && startio) 23365792b7feSMike Smith mlx_startio(sc); 23375792b7feSMike Smith 23385792b7feSMike Smith /* handle completion and timeouts */ 23395792b7feSMike Smith mlx_complete(sc); 23405792b7feSMike Smith 23415792b7feSMike Smith return(result); 23421ac4b82bSMike Smith } 23431ac4b82bSMike Smith 23441ac4b82bSMike Smith /******************************************************************************** 23455792b7feSMike Smith * Perform post-completion processing for commands on (sc). 23461ac4b82bSMike Smith */ 23471ac4b82bSMike Smith static void 23481ac4b82bSMike Smith mlx_complete(struct mlx_softc *sc) 23491ac4b82bSMike Smith { 23501ac4b82bSMike Smith struct mlx_command *mc, *nc; 23511ac4b82bSMike Smith 2352da8bb3a3SMike Smith debug_called(2); 23530fca6f8bSJohn Baldwin MLX_IO_ASSERT_LOCKED(sc); 23541ac4b82bSMike Smith 23555792b7feSMike Smith /* scan the list of busy/done commands */ 23564b006d7bSMike Smith mc = TAILQ_FIRST(&sc->mlx_work); 23571ac4b82bSMike Smith while (mc != NULL) { 23581ac4b82bSMike Smith nc = TAILQ_NEXT(mc, mc_link); 23591ac4b82bSMike Smith 23605792b7feSMike Smith /* Command has been completed in some fashion */ 23614b006d7bSMike Smith if (mc->mc_status != MLX_STATUS_BUSY) { 23624b006d7bSMike Smith 23635792b7feSMike Smith /* unmap the command's data buffer */ 23645792b7feSMike Smith mlx_unmapcmd(mc); 23651ac4b82bSMike Smith /* 23661ac4b82bSMike Smith * Does the command have a completion handler? 23671ac4b82bSMike Smith */ 23681ac4b82bSMike Smith if (mc->mc_complete != NULL) { 23691ac4b82bSMike Smith /* remove from list and give to handler */ 23704b006d7bSMike Smith TAILQ_REMOVE(&sc->mlx_work, mc, mc_link); 23711ac4b82bSMike Smith mc->mc_complete(mc); 23721ac4b82bSMike Smith 23731ac4b82bSMike Smith /* 23741ac4b82bSMike Smith * Is there a sleeper waiting on this command? 23751ac4b82bSMike Smith */ 23761ac4b82bSMike Smith } else if (mc->mc_private != NULL) { /* sleeping caller wants to know about it */ 23771ac4b82bSMike Smith 23781ac4b82bSMike Smith /* remove from list and wake up sleeper */ 23794b006d7bSMike Smith TAILQ_REMOVE(&sc->mlx_work, mc, mc_link); 23801ac4b82bSMike Smith wakeup_one(mc->mc_private); 23811ac4b82bSMike Smith 23821ac4b82bSMike Smith /* 23831ac4b82bSMike Smith * Leave the command for a caller that's polling for it. 23841ac4b82bSMike Smith */ 23851ac4b82bSMike Smith } else { 23861ac4b82bSMike Smith } 23874b006d7bSMike Smith } 23881ac4b82bSMike Smith mc = nc; 23891ac4b82bSMike Smith } 23901ac4b82bSMike Smith } 23911ac4b82bSMike Smith 23921ac4b82bSMike Smith /******************************************************************************** 23931ac4b82bSMike Smith ******************************************************************************** 23941ac4b82bSMike Smith Command Buffer Management 23951ac4b82bSMike Smith ******************************************************************************** 23961ac4b82bSMike Smith ********************************************************************************/ 23971ac4b82bSMike Smith 23981ac4b82bSMike Smith /******************************************************************************** 23991ac4b82bSMike Smith * Get a new command buffer. 24001ac4b82bSMike Smith * 24011ac4b82bSMike Smith * This may return NULL in low-memory cases. 24021ac4b82bSMike Smith * 24031ac4b82bSMike Smith * Note that using malloc() is expensive (the command buffer is << 1 page) but 24041ac4b82bSMike Smith * necessary if we are to be a loadable module before the zone allocator is fixed. 24051ac4b82bSMike Smith * 24061ac4b82bSMike Smith * If possible, we recycle a command buffer that's been used before. 24071ac4b82bSMike Smith * 24081ac4b82bSMike Smith * XXX Note that command buffers are not cleaned out - it is the caller's 24091ac4b82bSMike Smith * responsibility to ensure that all required fields are filled in before 24101ac4b82bSMike Smith * using a buffer. 24111ac4b82bSMike Smith */ 24121ac4b82bSMike Smith static struct mlx_command * 24131ac4b82bSMike Smith mlx_alloccmd(struct mlx_softc *sc) 24141ac4b82bSMike Smith { 24151ac4b82bSMike Smith struct mlx_command *mc; 24161ac4b82bSMike Smith int error; 24171ac4b82bSMike Smith 2418da8bb3a3SMike Smith debug_called(1); 24191ac4b82bSMike Smith 24200fca6f8bSJohn Baldwin MLX_IO_ASSERT_LOCKED(sc); 24211ac4b82bSMike Smith if ((mc = TAILQ_FIRST(&sc->mlx_freecmds)) != NULL) 24221ac4b82bSMike Smith TAILQ_REMOVE(&sc->mlx_freecmds, mc, mc_link); 24231ac4b82bSMike Smith 24241ac4b82bSMike Smith /* allocate a new command buffer? */ 24251ac4b82bSMike Smith if (mc == NULL) { 2426ca89ee27SDavid Malone mc = (struct mlx_command *)malloc(sizeof(*mc), M_DEVBUF, M_NOWAIT | M_ZERO); 24271ac4b82bSMike Smith if (mc != NULL) { 24281ac4b82bSMike Smith mc->mc_sc = sc; 24291ac4b82bSMike Smith error = bus_dmamap_create(sc->mlx_buffer_dmat, 0, &mc->mc_dmamap); 24301ac4b82bSMike Smith if (error) { 24311ac4b82bSMike Smith free(mc, M_DEVBUF); 24321ac4b82bSMike Smith return(NULL); 24331ac4b82bSMike Smith } 24341ac4b82bSMike Smith } 24351ac4b82bSMike Smith } 24361ac4b82bSMike Smith return(mc); 24371ac4b82bSMike Smith } 24381ac4b82bSMike Smith 24391ac4b82bSMike Smith /******************************************************************************** 24401ac4b82bSMike Smith * Release a command buffer for recycling. 24411ac4b82bSMike Smith * 24421ac4b82bSMike Smith * XXX It might be a good idea to limit the number of commands we save for reuse 24431ac4b82bSMike Smith * if it's shown that this list bloats out massively. 24441ac4b82bSMike Smith */ 24451ac4b82bSMike Smith static void 24461ac4b82bSMike Smith mlx_releasecmd(struct mlx_command *mc) 24471ac4b82bSMike Smith { 24481ac4b82bSMike Smith 2449da8bb3a3SMike Smith debug_called(1); 24501ac4b82bSMike Smith 24510fca6f8bSJohn Baldwin MLX_IO_ASSERT_LOCKED(mc->mc_sc); 24521ac4b82bSMike Smith TAILQ_INSERT_HEAD(&mc->mc_sc->mlx_freecmds, mc, mc_link); 24531ac4b82bSMike Smith } 24541ac4b82bSMike Smith 24551ac4b82bSMike Smith /******************************************************************************** 24561ac4b82bSMike Smith * Permanently discard a command buffer. 24571ac4b82bSMike Smith */ 24581ac4b82bSMike Smith static void 24591ac4b82bSMike Smith mlx_freecmd(struct mlx_command *mc) 24601ac4b82bSMike Smith { 24611ac4b82bSMike Smith struct mlx_softc *sc = mc->mc_sc; 24621ac4b82bSMike Smith 2463da8bb3a3SMike Smith debug_called(1); 24641ac4b82bSMike Smith bus_dmamap_destroy(sc->mlx_buffer_dmat, mc->mc_dmamap); 24651ac4b82bSMike Smith free(mc, M_DEVBUF); 24661ac4b82bSMike Smith } 24671ac4b82bSMike Smith 24681ac4b82bSMike Smith 24691ac4b82bSMike Smith /******************************************************************************** 24701ac4b82bSMike Smith ******************************************************************************** 24711ac4b82bSMike Smith Type 3 interface accessor methods 24721ac4b82bSMike Smith ******************************************************************************** 24731ac4b82bSMike Smith ********************************************************************************/ 24741ac4b82bSMike Smith 24751ac4b82bSMike Smith /******************************************************************************** 24761ac4b82bSMike Smith * Try to give (mc) to the controller. Returns 1 if successful, 0 on failure 24771ac4b82bSMike Smith * (the controller is not ready to take a command). 24781ac4b82bSMike Smith */ 24791ac4b82bSMike Smith static int 24801ac4b82bSMike Smith mlx_v3_tryqueue(struct mlx_softc *sc, struct mlx_command *mc) 24811ac4b82bSMike Smith { 24821ac4b82bSMike Smith int i; 24831ac4b82bSMike Smith 2484da8bb3a3SMike Smith debug_called(2); 24850fca6f8bSJohn Baldwin MLX_IO_ASSERT_LOCKED(sc); 24861ac4b82bSMike Smith 24871ac4b82bSMike Smith /* ready for our command? */ 24881ac4b82bSMike Smith if (!(MLX_V3_GET_IDBR(sc) & MLX_V3_IDB_FULL)) { 24891ac4b82bSMike Smith /* copy mailbox data to window */ 24901ac4b82bSMike Smith for (i = 0; i < 13; i++) 24911ac4b82bSMike Smith MLX_V3_PUT_MAILBOX(sc, i, mc->mc_mailbox[i]); 24921ac4b82bSMike Smith 24931ac4b82bSMike Smith /* post command */ 2494f6b84b08SMike Smith MLX_V3_PUT_IDBR(sc, MLX_V3_IDB_FULL); 24951ac4b82bSMike Smith return(1); 24961ac4b82bSMike Smith } 24971ac4b82bSMike Smith return(0); 24981ac4b82bSMike Smith } 24991ac4b82bSMike Smith 25001ac4b82bSMike Smith /******************************************************************************** 25011ac4b82bSMike Smith * See if a command has been completed, if so acknowledge its completion 25021ac4b82bSMike Smith * and recover the slot number and status code. 25031ac4b82bSMike Smith */ 25041ac4b82bSMike Smith static int 25051ac4b82bSMike Smith mlx_v3_findcomplete(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status) 25061ac4b82bSMike Smith { 25071ac4b82bSMike Smith 2508da8bb3a3SMike Smith debug_called(2); 25090fca6f8bSJohn Baldwin MLX_IO_ASSERT_LOCKED(sc); 25101ac4b82bSMike Smith 25111ac4b82bSMike Smith /* status available? */ 25121ac4b82bSMike Smith if (MLX_V3_GET_ODBR(sc) & MLX_V3_ODB_SAVAIL) { 25131ac4b82bSMike Smith *slot = MLX_V3_GET_STATUS_IDENT(sc); /* get command identifier */ 25141ac4b82bSMike Smith *status = MLX_V3_GET_STATUS(sc); /* get status */ 25151ac4b82bSMike Smith 25161ac4b82bSMike Smith /* acknowledge completion */ 2517f6b84b08SMike Smith MLX_V3_PUT_ODBR(sc, MLX_V3_ODB_SAVAIL); 2518f6b84b08SMike Smith MLX_V3_PUT_IDBR(sc, MLX_V3_IDB_SACK); 25191ac4b82bSMike Smith return(1); 25201ac4b82bSMike Smith } 25211ac4b82bSMike Smith return(0); 25221ac4b82bSMike Smith } 25231ac4b82bSMike Smith 25241ac4b82bSMike Smith /******************************************************************************** 25251ac4b82bSMike Smith * Enable/disable interrupts as requested. (No acknowledge required) 25261ac4b82bSMike Smith */ 25271ac4b82bSMike Smith static void 25281ac4b82bSMike Smith mlx_v3_intaction(struct mlx_softc *sc, int action) 25291ac4b82bSMike Smith { 2530da8bb3a3SMike Smith debug_called(1); 25310fca6f8bSJohn Baldwin MLX_IO_ASSERT_LOCKED(sc); 25321ac4b82bSMike Smith 25331ac4b82bSMike Smith switch(action) { 25341ac4b82bSMike Smith case MLX_INTACTION_DISABLE: 25351ac4b82bSMike Smith MLX_V3_PUT_IER(sc, 0); 25361ac4b82bSMike Smith sc->mlx_state &= ~MLX_STATE_INTEN; 25371ac4b82bSMike Smith break; 25381ac4b82bSMike Smith case MLX_INTACTION_ENABLE: 25391ac4b82bSMike Smith MLX_V3_PUT_IER(sc, 1); 25401ac4b82bSMike Smith sc->mlx_state |= MLX_STATE_INTEN; 25411ac4b82bSMike Smith break; 25421ac4b82bSMike Smith } 25431ac4b82bSMike Smith } 25441ac4b82bSMike Smith 2545da8bb3a3SMike Smith /******************************************************************************** 2546da8bb3a3SMike Smith * Poll for firmware error codes during controller initialisation. 2547da8bb3a3SMike Smith * Returns 0 if initialisation is complete, 1 if still in progress but no 2548da8bb3a3SMike Smith * error has been fetched, 2 if an error has been retrieved. 2549da8bb3a3SMike Smith */ 2550da8bb3a3SMike Smith static int 25510fca6f8bSJohn Baldwin mlx_v3_fw_handshake(struct mlx_softc *sc, int *error, int *param1, int *param2, 25520fca6f8bSJohn Baldwin int first) 2553da8bb3a3SMike Smith { 2554da8bb3a3SMike Smith u_int8_t fwerror; 2555da8bb3a3SMike Smith 2556da8bb3a3SMike Smith debug_called(2); 2557da8bb3a3SMike Smith 2558da8bb3a3SMike Smith /* first time around, clear any hardware completion status */ 25590fca6f8bSJohn Baldwin if (first) { 2560da8bb3a3SMike Smith MLX_V3_PUT_IDBR(sc, MLX_V3_IDB_SACK); 2561da8bb3a3SMike Smith DELAY(1000); 2562da8bb3a3SMike Smith } 2563da8bb3a3SMike Smith 2564da8bb3a3SMike Smith /* init in progress? */ 2565da8bb3a3SMike Smith if (!(MLX_V3_GET_IDBR(sc) & MLX_V3_IDB_INIT_BUSY)) 2566da8bb3a3SMike Smith return(0); 2567da8bb3a3SMike Smith 2568da8bb3a3SMike Smith /* test error value */ 2569da8bb3a3SMike Smith fwerror = MLX_V3_GET_FWERROR(sc); 2570da8bb3a3SMike Smith if (!(fwerror & MLX_V3_FWERROR_PEND)) 2571da8bb3a3SMike Smith return(1); 2572da8bb3a3SMike Smith 2573da8bb3a3SMike Smith /* mask status pending bit, fetch status */ 2574da8bb3a3SMike Smith *error = fwerror & ~MLX_V3_FWERROR_PEND; 2575da8bb3a3SMike Smith *param1 = MLX_V3_GET_FWERROR_PARAM1(sc); 2576da8bb3a3SMike Smith *param2 = MLX_V3_GET_FWERROR_PARAM2(sc); 2577da8bb3a3SMike Smith 2578da8bb3a3SMike Smith /* acknowledge */ 2579da8bb3a3SMike Smith MLX_V3_PUT_FWERROR(sc, 0); 2580da8bb3a3SMike Smith 2581da8bb3a3SMike Smith return(2); 2582da8bb3a3SMike Smith } 25831ac4b82bSMike Smith 25841ac4b82bSMike Smith /******************************************************************************** 25851ac4b82bSMike Smith ******************************************************************************** 2586f6b84b08SMike Smith Type 4 interface accessor methods 2587f6b84b08SMike Smith ******************************************************************************** 2588f6b84b08SMike Smith ********************************************************************************/ 2589f6b84b08SMike Smith 2590f6b84b08SMike Smith /******************************************************************************** 2591f6b84b08SMike Smith * Try to give (mc) to the controller. Returns 1 if successful, 0 on failure 2592f6b84b08SMike Smith * (the controller is not ready to take a command). 2593f6b84b08SMike Smith */ 2594f6b84b08SMike Smith static int 2595f6b84b08SMike Smith mlx_v4_tryqueue(struct mlx_softc *sc, struct mlx_command *mc) 2596f6b84b08SMike Smith { 2597f6b84b08SMike Smith int i; 2598f6b84b08SMike Smith 2599da8bb3a3SMike Smith debug_called(2); 26000fca6f8bSJohn Baldwin MLX_IO_ASSERT_LOCKED(sc); 2601f6b84b08SMike Smith 2602f6b84b08SMike Smith /* ready for our command? */ 2603f6b84b08SMike Smith if (!(MLX_V4_GET_IDBR(sc) & MLX_V4_IDB_FULL)) { 2604f6b84b08SMike Smith /* copy mailbox data to window */ 2605f6b84b08SMike Smith for (i = 0; i < 13; i++) 2606f6b84b08SMike Smith MLX_V4_PUT_MAILBOX(sc, i, mc->mc_mailbox[i]); 2607f6b84b08SMike Smith 2608da8bb3a3SMike Smith /* memory-mapped controller, so issue a write barrier to ensure the mailbox is filled */ 26090fca6f8bSJohn Baldwin bus_barrier(sc->mlx_mem, MLX_V4_MAILBOX, MLX_V4_MAILBOX_LENGTH, 2610da8bb3a3SMike Smith BUS_SPACE_BARRIER_WRITE); 2611da8bb3a3SMike Smith 2612f6b84b08SMike Smith /* post command */ 2613f6b84b08SMike Smith MLX_V4_PUT_IDBR(sc, MLX_V4_IDB_HWMBOX_CMD); 2614f6b84b08SMike Smith return(1); 2615f6b84b08SMike Smith } 2616f6b84b08SMike Smith return(0); 2617f6b84b08SMike Smith } 2618f6b84b08SMike Smith 2619f6b84b08SMike Smith /******************************************************************************** 2620f6b84b08SMike Smith * See if a command has been completed, if so acknowledge its completion 2621f6b84b08SMike Smith * and recover the slot number and status code. 2622f6b84b08SMike Smith */ 2623f6b84b08SMike Smith static int 2624f6b84b08SMike Smith mlx_v4_findcomplete(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status) 2625f6b84b08SMike Smith { 2626f6b84b08SMike Smith 2627da8bb3a3SMike Smith debug_called(2); 26280fca6f8bSJohn Baldwin MLX_IO_ASSERT_LOCKED(sc); 2629f6b84b08SMike Smith 2630f6b84b08SMike Smith /* status available? */ 2631f6b84b08SMike Smith if (MLX_V4_GET_ODBR(sc) & MLX_V4_ODB_HWSAVAIL) { 2632f6b84b08SMike Smith *slot = MLX_V4_GET_STATUS_IDENT(sc); /* get command identifier */ 2633f6b84b08SMike Smith *status = MLX_V4_GET_STATUS(sc); /* get status */ 2634f6b84b08SMike Smith 2635f6b84b08SMike Smith /* acknowledge completion */ 2636f6b84b08SMike Smith MLX_V4_PUT_ODBR(sc, MLX_V4_ODB_HWMBOX_ACK); 2637f6b84b08SMike Smith MLX_V4_PUT_IDBR(sc, MLX_V4_IDB_SACK); 2638f6b84b08SMike Smith return(1); 2639f6b84b08SMike Smith } 2640f6b84b08SMike Smith return(0); 2641f6b84b08SMike Smith } 2642f6b84b08SMike Smith 2643f6b84b08SMike Smith /******************************************************************************** 2644f6b84b08SMike Smith * Enable/disable interrupts as requested. 2645f6b84b08SMike Smith */ 2646f6b84b08SMike Smith static void 2647f6b84b08SMike Smith mlx_v4_intaction(struct mlx_softc *sc, int action) 2648f6b84b08SMike Smith { 2649da8bb3a3SMike Smith debug_called(1); 26500fca6f8bSJohn Baldwin MLX_IO_ASSERT_LOCKED(sc); 2651f6b84b08SMike Smith 2652f6b84b08SMike Smith switch(action) { 2653f6b84b08SMike Smith case MLX_INTACTION_DISABLE: 2654f6b84b08SMike Smith MLX_V4_PUT_IER(sc, MLX_V4_IER_MASK | MLX_V4_IER_DISINT); 2655f6b84b08SMike Smith sc->mlx_state &= ~MLX_STATE_INTEN; 2656f6b84b08SMike Smith break; 2657f6b84b08SMike Smith case MLX_INTACTION_ENABLE: 2658f6b84b08SMike Smith MLX_V4_PUT_IER(sc, MLX_V4_IER_MASK & ~MLX_V4_IER_DISINT); 2659f6b84b08SMike Smith sc->mlx_state |= MLX_STATE_INTEN; 2660f6b84b08SMike Smith break; 2661f6b84b08SMike Smith } 2662f6b84b08SMike Smith } 2663f6b84b08SMike Smith 2664da8bb3a3SMike Smith /******************************************************************************** 2665da8bb3a3SMike Smith * Poll for firmware error codes during controller initialisation. 2666da8bb3a3SMike Smith * Returns 0 if initialisation is complete, 1 if still in progress but no 2667da8bb3a3SMike Smith * error has been fetched, 2 if an error has been retrieved. 2668da8bb3a3SMike Smith */ 2669da8bb3a3SMike Smith static int 26700fca6f8bSJohn Baldwin mlx_v4_fw_handshake(struct mlx_softc *sc, int *error, int *param1, int *param2, 26710fca6f8bSJohn Baldwin int first) 2672da8bb3a3SMike Smith { 2673da8bb3a3SMike Smith u_int8_t fwerror; 2674da8bb3a3SMike Smith 2675da8bb3a3SMike Smith debug_called(2); 2676da8bb3a3SMike Smith 2677da8bb3a3SMike Smith /* first time around, clear any hardware completion status */ 26780fca6f8bSJohn Baldwin if (first) { 2679da8bb3a3SMike Smith MLX_V4_PUT_IDBR(sc, MLX_V4_IDB_SACK); 2680da8bb3a3SMike Smith DELAY(1000); 2681da8bb3a3SMike Smith } 2682da8bb3a3SMike Smith 2683da8bb3a3SMike Smith /* init in progress? */ 2684da8bb3a3SMike Smith if (!(MLX_V4_GET_IDBR(sc) & MLX_V4_IDB_INIT_BUSY)) 2685da8bb3a3SMike Smith return(0); 2686da8bb3a3SMike Smith 2687da8bb3a3SMike Smith /* test error value */ 2688da8bb3a3SMike Smith fwerror = MLX_V4_GET_FWERROR(sc); 2689da8bb3a3SMike Smith if (!(fwerror & MLX_V4_FWERROR_PEND)) 2690da8bb3a3SMike Smith return(1); 2691da8bb3a3SMike Smith 2692da8bb3a3SMike Smith /* mask status pending bit, fetch status */ 2693da8bb3a3SMike Smith *error = fwerror & ~MLX_V4_FWERROR_PEND; 2694da8bb3a3SMike Smith *param1 = MLX_V4_GET_FWERROR_PARAM1(sc); 2695da8bb3a3SMike Smith *param2 = MLX_V4_GET_FWERROR_PARAM2(sc); 2696da8bb3a3SMike Smith 2697da8bb3a3SMike Smith /* acknowledge */ 2698da8bb3a3SMike Smith MLX_V4_PUT_FWERROR(sc, 0); 2699da8bb3a3SMike Smith 2700da8bb3a3SMike Smith return(2); 2701da8bb3a3SMike Smith } 2702f6b84b08SMike Smith 2703f6b84b08SMike Smith /******************************************************************************** 2704f6b84b08SMike Smith ******************************************************************************** 27055792b7feSMike Smith Type 5 interface accessor methods 27065792b7feSMike Smith ******************************************************************************** 27075792b7feSMike Smith ********************************************************************************/ 27085792b7feSMike Smith 27095792b7feSMike Smith /******************************************************************************** 27105792b7feSMike Smith * Try to give (mc) to the controller. Returns 1 if successful, 0 on failure 27115792b7feSMike Smith * (the controller is not ready to take a command). 27125792b7feSMike Smith */ 27135792b7feSMike Smith static int 27145792b7feSMike Smith mlx_v5_tryqueue(struct mlx_softc *sc, struct mlx_command *mc) 27155792b7feSMike Smith { 27165792b7feSMike Smith int i; 27175792b7feSMike Smith 2718da8bb3a3SMike Smith debug_called(2); 27190fca6f8bSJohn Baldwin MLX_IO_ASSERT_LOCKED(sc); 27205792b7feSMike Smith 27215792b7feSMike Smith /* ready for our command? */ 27225792b7feSMike Smith if (MLX_V5_GET_IDBR(sc) & MLX_V5_IDB_EMPTY) { 27235792b7feSMike Smith /* copy mailbox data to window */ 27245792b7feSMike Smith for (i = 0; i < 13; i++) 27255792b7feSMike Smith MLX_V5_PUT_MAILBOX(sc, i, mc->mc_mailbox[i]); 27265792b7feSMike Smith 27275792b7feSMike Smith /* post command */ 27285792b7feSMike Smith MLX_V5_PUT_IDBR(sc, MLX_V5_IDB_HWMBOX_CMD); 27295792b7feSMike Smith return(1); 27305792b7feSMike Smith } 27315792b7feSMike Smith return(0); 27325792b7feSMike Smith } 27335792b7feSMike Smith 27345792b7feSMike Smith /******************************************************************************** 27355792b7feSMike Smith * See if a command has been completed, if so acknowledge its completion 27365792b7feSMike Smith * and recover the slot number and status code. 27375792b7feSMike Smith */ 27385792b7feSMike Smith static int 27395792b7feSMike Smith mlx_v5_findcomplete(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status) 27405792b7feSMike Smith { 27415792b7feSMike Smith 2742da8bb3a3SMike Smith debug_called(2); 27430fca6f8bSJohn Baldwin MLX_IO_ASSERT_LOCKED(sc); 27445792b7feSMike Smith 27455792b7feSMike Smith /* status available? */ 27465792b7feSMike Smith if (MLX_V5_GET_ODBR(sc) & MLX_V5_ODB_HWSAVAIL) { 27475792b7feSMike Smith *slot = MLX_V5_GET_STATUS_IDENT(sc); /* get command identifier */ 27485792b7feSMike Smith *status = MLX_V5_GET_STATUS(sc); /* get status */ 27495792b7feSMike Smith 27505792b7feSMike Smith /* acknowledge completion */ 27515792b7feSMike Smith MLX_V5_PUT_ODBR(sc, MLX_V5_ODB_HWMBOX_ACK); 27525792b7feSMike Smith MLX_V5_PUT_IDBR(sc, MLX_V5_IDB_SACK); 27535792b7feSMike Smith return(1); 27545792b7feSMike Smith } 27555792b7feSMike Smith return(0); 27565792b7feSMike Smith } 27575792b7feSMike Smith 27585792b7feSMike Smith /******************************************************************************** 27595792b7feSMike Smith * Enable/disable interrupts as requested. 27605792b7feSMike Smith */ 27615792b7feSMike Smith static void 27625792b7feSMike Smith mlx_v5_intaction(struct mlx_softc *sc, int action) 27635792b7feSMike Smith { 2764da8bb3a3SMike Smith debug_called(1); 27650fca6f8bSJohn Baldwin MLX_IO_ASSERT_LOCKED(sc); 27665792b7feSMike Smith 27675792b7feSMike Smith switch(action) { 27685792b7feSMike Smith case MLX_INTACTION_DISABLE: 2769da8bb3a3SMike Smith MLX_V5_PUT_IER(sc, 0xff & MLX_V5_IER_DISINT); 27705792b7feSMike Smith sc->mlx_state &= ~MLX_STATE_INTEN; 27715792b7feSMike Smith break; 27725792b7feSMike Smith case MLX_INTACTION_ENABLE: 2773da8bb3a3SMike Smith MLX_V5_PUT_IER(sc, 0xff & ~MLX_V5_IER_DISINT); 27745792b7feSMike Smith sc->mlx_state |= MLX_STATE_INTEN; 27755792b7feSMike Smith break; 27765792b7feSMike Smith } 27775792b7feSMike Smith } 27785792b7feSMike Smith 2779da8bb3a3SMike Smith /******************************************************************************** 2780da8bb3a3SMike Smith * Poll for firmware error codes during controller initialisation. 2781da8bb3a3SMike Smith * Returns 0 if initialisation is complete, 1 if still in progress but no 2782da8bb3a3SMike Smith * error has been fetched, 2 if an error has been retrieved. 2783da8bb3a3SMike Smith */ 2784da8bb3a3SMike Smith static int 27850fca6f8bSJohn Baldwin mlx_v5_fw_handshake(struct mlx_softc *sc, int *error, int *param1, int *param2, 27860fca6f8bSJohn Baldwin int first) 2787da8bb3a3SMike Smith { 2788da8bb3a3SMike Smith u_int8_t fwerror; 2789da8bb3a3SMike Smith 2790da8bb3a3SMike Smith debug_called(2); 2791da8bb3a3SMike Smith 2792da8bb3a3SMike Smith /* first time around, clear any hardware completion status */ 27930fca6f8bSJohn Baldwin if (first) { 2794da8bb3a3SMike Smith MLX_V5_PUT_IDBR(sc, MLX_V5_IDB_SACK); 2795da8bb3a3SMike Smith DELAY(1000); 2796da8bb3a3SMike Smith } 2797da8bb3a3SMike Smith 2798da8bb3a3SMike Smith /* init in progress? */ 2799da8bb3a3SMike Smith if (MLX_V5_GET_IDBR(sc) & MLX_V5_IDB_INIT_DONE) 2800da8bb3a3SMike Smith return(0); 2801da8bb3a3SMike Smith 2802da8bb3a3SMike Smith /* test for error value */ 2803da8bb3a3SMike Smith fwerror = MLX_V5_GET_FWERROR(sc); 2804da8bb3a3SMike Smith if (!(fwerror & MLX_V5_FWERROR_PEND)) 2805da8bb3a3SMike Smith return(1); 2806da8bb3a3SMike Smith 2807da8bb3a3SMike Smith /* mask status pending bit, fetch status */ 2808da8bb3a3SMike Smith *error = fwerror & ~MLX_V5_FWERROR_PEND; 2809da8bb3a3SMike Smith *param1 = MLX_V5_GET_FWERROR_PARAM1(sc); 2810da8bb3a3SMike Smith *param2 = MLX_V5_GET_FWERROR_PARAM2(sc); 2811da8bb3a3SMike Smith 2812da8bb3a3SMike Smith /* acknowledge */ 2813da8bb3a3SMike Smith MLX_V5_PUT_FWERROR(sc, 0xff); 2814da8bb3a3SMike Smith 2815da8bb3a3SMike Smith return(2); 2816da8bb3a3SMike Smith } 28175792b7feSMike Smith 28185792b7feSMike Smith /******************************************************************************** 28195792b7feSMike Smith ******************************************************************************** 28201ac4b82bSMike Smith Debugging 28211ac4b82bSMike Smith ******************************************************************************** 28221ac4b82bSMike Smith ********************************************************************************/ 28231ac4b82bSMike Smith 28241ac4b82bSMike Smith /******************************************************************************** 28251ac4b82bSMike Smith * Return a status message describing (mc) 28261ac4b82bSMike Smith */ 28271ac4b82bSMike Smith static char *mlx_status_messages[] = { 28281ac4b82bSMike Smith "normal completion", /* 00 */ 28291ac4b82bSMike Smith "irrecoverable data error", /* 01 */ 28301ac4b82bSMike Smith "drive does not exist, or is offline", /* 02 */ 28311ac4b82bSMike Smith "attempt to write beyond end of drive", /* 03 */ 28321ac4b82bSMike Smith "bad data encountered", /* 04 */ 28331ac4b82bSMike Smith "invalid log entry request", /* 05 */ 28341ac4b82bSMike Smith "attempt to rebuild online drive", /* 06 */ 28351ac4b82bSMike Smith "new disk failed during rebuild", /* 07 */ 28361ac4b82bSMike Smith "invalid channel/target", /* 08 */ 28371ac4b82bSMike Smith "rebuild/check already in progress", /* 09 */ 28381ac4b82bSMike Smith "one or more disks are dead", /* 10 */ 28391ac4b82bSMike Smith "invalid or non-redundant drive", /* 11 */ 28401ac4b82bSMike Smith "channel is busy", /* 12 */ 28411ac4b82bSMike Smith "channel is not stopped", /* 13 */ 2842da8bb3a3SMike Smith "rebuild successfully terminated", /* 14 */ 2843da8bb3a3SMike Smith "unsupported command", /* 15 */ 2844da8bb3a3SMike Smith "check condition received", /* 16 */ 2845da8bb3a3SMike Smith "device is busy", /* 17 */ 2846da8bb3a3SMike Smith "selection or command timeout", /* 18 */ 2847da8bb3a3SMike Smith "command terminated abnormally", /* 19 */ 2848da8bb3a3SMike Smith "" 28491ac4b82bSMike Smith }; 28501ac4b82bSMike Smith 28511ac4b82bSMike Smith static struct 28521ac4b82bSMike Smith { 28531ac4b82bSMike Smith int command; 28541ac4b82bSMike Smith u_int16_t status; 28551ac4b82bSMike Smith int msg; 28561ac4b82bSMike Smith } mlx_messages[] = { 2857da8bb3a3SMike Smith {MLX_CMD_READSG, 0x0001, 1}, 2858da8bb3a3SMike Smith {MLX_CMD_READSG, 0x0002, 1}, 2859da8bb3a3SMike Smith {MLX_CMD_READSG, 0x0105, 3}, 2860da8bb3a3SMike Smith {MLX_CMD_READSG, 0x010c, 4}, 2861da8bb3a3SMike Smith {MLX_CMD_WRITESG, 0x0001, 1}, 2862da8bb3a3SMike Smith {MLX_CMD_WRITESG, 0x0002, 1}, 2863da8bb3a3SMike Smith {MLX_CMD_WRITESG, 0x0105, 3}, 2864da8bb3a3SMike Smith {MLX_CMD_READSG_OLD, 0x0001, 1}, 2865da8bb3a3SMike Smith {MLX_CMD_READSG_OLD, 0x0002, 1}, 2866da8bb3a3SMike Smith {MLX_CMD_READSG_OLD, 0x0105, 3}, 2867da8bb3a3SMike Smith {MLX_CMD_WRITESG_OLD, 0x0001, 1}, 2868da8bb3a3SMike Smith {MLX_CMD_WRITESG_OLD, 0x0002, 1}, 2869da8bb3a3SMike Smith {MLX_CMD_WRITESG_OLD, 0x0105, 3}, 28701ac4b82bSMike Smith {MLX_CMD_LOGOP, 0x0105, 5}, 28711ac4b82bSMike Smith {MLX_CMD_REBUILDASYNC, 0x0002, 6}, 28721ac4b82bSMike Smith {MLX_CMD_REBUILDASYNC, 0x0004, 7}, 28731ac4b82bSMike Smith {MLX_CMD_REBUILDASYNC, 0x0105, 8}, 28741ac4b82bSMike Smith {MLX_CMD_REBUILDASYNC, 0x0106, 9}, 2875da8bb3a3SMike Smith {MLX_CMD_REBUILDASYNC, 0x0107, 14}, 28761ac4b82bSMike Smith {MLX_CMD_CHECKASYNC, 0x0002, 10}, 28771ac4b82bSMike Smith {MLX_CMD_CHECKASYNC, 0x0105, 11}, 28781ac4b82bSMike Smith {MLX_CMD_CHECKASYNC, 0x0106, 9}, 28791ac4b82bSMike Smith {MLX_CMD_STOPCHANNEL, 0x0106, 12}, 28801ac4b82bSMike Smith {MLX_CMD_STOPCHANNEL, 0x0105, 8}, 28811ac4b82bSMike Smith {MLX_CMD_STARTCHANNEL, 0x0005, 13}, 28821ac4b82bSMike Smith {MLX_CMD_STARTCHANNEL, 0x0105, 8}, 2883da8bb3a3SMike Smith {MLX_CMD_DIRECT_CDB, 0x0002, 16}, 2884da8bb3a3SMike Smith {MLX_CMD_DIRECT_CDB, 0x0008, 17}, 2885da8bb3a3SMike Smith {MLX_CMD_DIRECT_CDB, 0x000e, 18}, 2886da8bb3a3SMike Smith {MLX_CMD_DIRECT_CDB, 0x000f, 19}, 2887da8bb3a3SMike Smith {MLX_CMD_DIRECT_CDB, 0x0105, 8}, 2888da8bb3a3SMike Smith 2889da8bb3a3SMike Smith {0, 0x0104, 14}, 28901ac4b82bSMike Smith {-1, 0, 0} 28911ac4b82bSMike Smith }; 28921ac4b82bSMike Smith 28931ac4b82bSMike Smith static char * 28941ac4b82bSMike Smith mlx_diagnose_command(struct mlx_command *mc) 28951ac4b82bSMike Smith { 28961ac4b82bSMike Smith static char unkmsg[80]; 28971ac4b82bSMike Smith int i; 28981ac4b82bSMike Smith 28991ac4b82bSMike Smith /* look up message in table */ 29001ac4b82bSMike Smith for (i = 0; mlx_messages[i].command != -1; i++) 2901da8bb3a3SMike Smith if (((mc->mc_mailbox[0] == mlx_messages[i].command) || (mlx_messages[i].command == 0)) && 2902466454bdSMike Smith (mc->mc_status == mlx_messages[i].status)) 29031ac4b82bSMike Smith return(mlx_status_messages[mlx_messages[i].msg]); 29041ac4b82bSMike Smith 29051ac4b82bSMike Smith sprintf(unkmsg, "unknown response 0x%x for command 0x%x", (int)mc->mc_status, (int)mc->mc_mailbox[0]); 29061ac4b82bSMike Smith return(unkmsg); 29071ac4b82bSMike Smith } 29081ac4b82bSMike Smith 29091ac4b82bSMike Smith /******************************************************************************* 2910da8bb3a3SMike Smith * Print a string describing the controller (sc) 29111ac4b82bSMike Smith */ 29125792b7feSMike Smith static struct 29135792b7feSMike Smith { 29145792b7feSMike Smith int hwid; 29155792b7feSMike Smith char *name; 29165792b7feSMike Smith } mlx_controller_names[] = { 29175792b7feSMike Smith {0x01, "960P/PD"}, 29185792b7feSMike Smith {0x02, "960PL"}, 29195792b7feSMike Smith {0x10, "960PG"}, 29205792b7feSMike Smith {0x11, "960PJ"}, 29219eee27f1SMike Smith {0x12, "960PR"}, 29229eee27f1SMike Smith {0x13, "960PT"}, 29239eee27f1SMike Smith {0x14, "960PTL0"}, 29249eee27f1SMike Smith {0x15, "960PRL"}, 29259eee27f1SMike Smith {0x16, "960PTL1"}, 29269eee27f1SMike Smith {0x20, "1164PVX"}, 29275792b7feSMike Smith {-1, NULL} 29285792b7feSMike Smith }; 29295792b7feSMike Smith 29309eee27f1SMike Smith static void 29319eee27f1SMike Smith mlx_describe_controller(struct mlx_softc *sc) 29321ac4b82bSMike Smith { 29331ac4b82bSMike Smith static char buf[80]; 29345792b7feSMike Smith char *model; 29359eee27f1SMike Smith int i; 29361ac4b82bSMike Smith 29375792b7feSMike Smith for (i = 0, model = NULL; mlx_controller_names[i].name != NULL; i++) { 29389eee27f1SMike Smith if ((sc->mlx_enq2->me_hardware_id & 0xff) == mlx_controller_names[i].hwid) { 29395792b7feSMike Smith model = mlx_controller_names[i].name; 29401ac4b82bSMike Smith break; 29411ac4b82bSMike Smith } 29425792b7feSMike Smith } 29435792b7feSMike Smith if (model == NULL) { 29449eee27f1SMike Smith sprintf(buf, " model 0x%x", sc->mlx_enq2->me_hardware_id & 0xff); 29455792b7feSMike Smith model = buf; 29465792b7feSMike Smith } 2947da8bb3a3SMike Smith device_printf(sc->mlx_dev, "DAC%s, %d channel%s, firmware %d.%02d-%c-%02d, %dMB RAM\n", 29489eee27f1SMike Smith model, 29499eee27f1SMike Smith sc->mlx_enq2->me_actual_channels, 29509eee27f1SMike Smith sc->mlx_enq2->me_actual_channels > 1 ? "s" : "", 29519eee27f1SMike Smith sc->mlx_enq2->me_firmware_id & 0xff, 29529eee27f1SMike Smith (sc->mlx_enq2->me_firmware_id >> 8) & 0xff, 29539eee27f1SMike Smith (sc->mlx_enq2->me_firmware_id >> 24) & 0xff, 2954b9256fe3SMike Smith (sc->mlx_enq2->me_firmware_id >> 16) & 0xff, 29559eee27f1SMike Smith sc->mlx_enq2->me_mem_size / (1024 * 1024)); 29569eee27f1SMike Smith 29579eee27f1SMike Smith if (bootverbose) { 29589eee27f1SMike Smith device_printf(sc->mlx_dev, " Hardware ID 0x%08x\n", sc->mlx_enq2->me_hardware_id); 29599eee27f1SMike Smith device_printf(sc->mlx_dev, " Firmware ID 0x%08x\n", sc->mlx_enq2->me_firmware_id); 29609eee27f1SMike Smith device_printf(sc->mlx_dev, " Configured/Actual channels %d/%d\n", sc->mlx_enq2->me_configured_channels, 29619eee27f1SMike Smith sc->mlx_enq2->me_actual_channels); 29629eee27f1SMike Smith device_printf(sc->mlx_dev, " Max Targets %d\n", sc->mlx_enq2->me_max_targets); 29639eee27f1SMike Smith device_printf(sc->mlx_dev, " Max Tags %d\n", sc->mlx_enq2->me_max_tags); 29649eee27f1SMike Smith device_printf(sc->mlx_dev, " Max System Drives %d\n", sc->mlx_enq2->me_max_sys_drives); 29659eee27f1SMike Smith device_printf(sc->mlx_dev, " Max Arms %d\n", sc->mlx_enq2->me_max_arms); 29669eee27f1SMike Smith device_printf(sc->mlx_dev, " Max Spans %d\n", sc->mlx_enq2->me_max_spans); 29679eee27f1SMike Smith device_printf(sc->mlx_dev, " DRAM/cache/flash/NVRAM size %d/%d/%d/%d\n", sc->mlx_enq2->me_mem_size, 29689eee27f1SMike Smith sc->mlx_enq2->me_cache_size, sc->mlx_enq2->me_flash_size, sc->mlx_enq2->me_nvram_size); 29699eee27f1SMike Smith device_printf(sc->mlx_dev, " DRAM type %d\n", sc->mlx_enq2->me_mem_type); 29709eee27f1SMike Smith device_printf(sc->mlx_dev, " Clock Speed %dns\n", sc->mlx_enq2->me_clock_speed); 29719eee27f1SMike Smith device_printf(sc->mlx_dev, " Hardware Speed %dns\n", sc->mlx_enq2->me_hardware_speed); 29729eee27f1SMike Smith device_printf(sc->mlx_dev, " Max Commands %d\n", sc->mlx_enq2->me_max_commands); 29739eee27f1SMike Smith device_printf(sc->mlx_dev, " Max SG Entries %d\n", sc->mlx_enq2->me_max_sg); 29749eee27f1SMike Smith device_printf(sc->mlx_dev, " Max DP %d\n", sc->mlx_enq2->me_max_dp); 29759eee27f1SMike Smith device_printf(sc->mlx_dev, " Max IOD %d\n", sc->mlx_enq2->me_max_iod); 29769eee27f1SMike Smith device_printf(sc->mlx_dev, " Max Comb %d\n", sc->mlx_enq2->me_max_comb); 29779eee27f1SMike Smith device_printf(sc->mlx_dev, " Latency %ds\n", sc->mlx_enq2->me_latency); 29789eee27f1SMike Smith device_printf(sc->mlx_dev, " SCSI Timeout %ds\n", sc->mlx_enq2->me_scsi_timeout); 29799eee27f1SMike Smith device_printf(sc->mlx_dev, " Min Free Lines %d\n", sc->mlx_enq2->me_min_freelines); 29809eee27f1SMike Smith device_printf(sc->mlx_dev, " Rate Constant %d\n", sc->mlx_enq2->me_rate_const); 29819eee27f1SMike Smith device_printf(sc->mlx_dev, " MAXBLK %d\n", sc->mlx_enq2->me_maxblk); 29829eee27f1SMike Smith device_printf(sc->mlx_dev, " Blocking Factor %d sectors\n", sc->mlx_enq2->me_blocking_factor); 29839eee27f1SMike Smith device_printf(sc->mlx_dev, " Cache Line Size %d blocks\n", sc->mlx_enq2->me_cacheline); 29849eee27f1SMike Smith device_printf(sc->mlx_dev, " SCSI Capability %s%dMHz, %d bit\n", 29859eee27f1SMike Smith sc->mlx_enq2->me_scsi_cap & (1<<4) ? "differential " : "", 29869eee27f1SMike Smith (1 << ((sc->mlx_enq2->me_scsi_cap >> 2) & 3)) * 10, 29879eee27f1SMike Smith 8 << (sc->mlx_enq2->me_scsi_cap & 0x3)); 29889eee27f1SMike Smith device_printf(sc->mlx_dev, " Firmware Build Number %d\n", sc->mlx_enq2->me_firmware_build); 29899eee27f1SMike Smith device_printf(sc->mlx_dev, " Fault Management Type %d\n", sc->mlx_enq2->me_fault_mgmt_type); 29909eee27f1SMike Smith device_printf(sc->mlx_dev, " Features %b\n", sc->mlx_enq2->me_firmware_features, 29919eee27f1SMike Smith "\20\4Background Init\3Read Ahead\2MORE\1Cluster\n"); 29929eee27f1SMike Smith 29939eee27f1SMike Smith } 29941ac4b82bSMike Smith } 29951ac4b82bSMike Smith 2996da8bb3a3SMike Smith /******************************************************************************* 2997da8bb3a3SMike Smith * Emit a string describing the firmware handshake status code, and return a flag 2998da8bb3a3SMike Smith * indicating whether the code represents a fatal error. 2999da8bb3a3SMike Smith * 3000da8bb3a3SMike Smith * Error code interpretations are from the Linux driver, and don't directly match 3001da8bb3a3SMike Smith * the messages printed by Mylex's BIOS. This may change if documentation on the 3002da8bb3a3SMike Smith * codes is forthcoming. 3003da8bb3a3SMike Smith */ 3004da8bb3a3SMike Smith static int 3005da8bb3a3SMike Smith mlx_fw_message(struct mlx_softc *sc, int error, int param1, int param2) 3006da8bb3a3SMike Smith { 3007da8bb3a3SMike Smith switch(error) { 3008da8bb3a3SMike Smith case 0x00: 3009da8bb3a3SMike Smith device_printf(sc->mlx_dev, "physical drive %d:%d not responding\n", param2, param1); 3010da8bb3a3SMike Smith break; 3011da8bb3a3SMike Smith case 0x08: 3012da8bb3a3SMike Smith /* we could be neater about this and give some indication when we receive more of them */ 3013da8bb3a3SMike Smith if (!(sc->mlx_flags & MLX_SPINUP_REPORTED)) { 3014da8bb3a3SMike Smith device_printf(sc->mlx_dev, "spinning up drives...\n"); 3015da8bb3a3SMike Smith sc->mlx_flags |= MLX_SPINUP_REPORTED; 3016da8bb3a3SMike Smith } 3017da8bb3a3SMike Smith break; 3018da8bb3a3SMike Smith case 0x30: 3019da8bb3a3SMike Smith device_printf(sc->mlx_dev, "configuration checksum error\n"); 3020da8bb3a3SMike Smith break; 3021da8bb3a3SMike Smith case 0x60: 3022da8bb3a3SMike Smith device_printf(sc->mlx_dev, "mirror race recovery failed\n"); 3023da8bb3a3SMike Smith break; 3024da8bb3a3SMike Smith case 0x70: 3025da8bb3a3SMike Smith device_printf(sc->mlx_dev, "mirror race recovery in progress\n"); 3026da8bb3a3SMike Smith break; 3027da8bb3a3SMike Smith case 0x90: 3028da8bb3a3SMike Smith device_printf(sc->mlx_dev, "physical drive %d:%d COD mismatch\n", param2, param1); 3029da8bb3a3SMike Smith break; 3030da8bb3a3SMike Smith case 0xa0: 3031da8bb3a3SMike Smith device_printf(sc->mlx_dev, "logical drive installation aborted\n"); 3032da8bb3a3SMike Smith break; 3033da8bb3a3SMike Smith case 0xb0: 3034da8bb3a3SMike Smith device_printf(sc->mlx_dev, "mirror race on a critical system drive\n"); 3035da8bb3a3SMike Smith break; 3036da8bb3a3SMike Smith case 0xd0: 3037da8bb3a3SMike Smith device_printf(sc->mlx_dev, "new controller configuration found\n"); 3038da8bb3a3SMike Smith break; 3039da8bb3a3SMike Smith case 0xf0: 3040da8bb3a3SMike Smith device_printf(sc->mlx_dev, "FATAL MEMORY PARITY ERROR\n"); 3041da8bb3a3SMike Smith return(1); 3042da8bb3a3SMike Smith default: 3043da8bb3a3SMike Smith device_printf(sc->mlx_dev, "unknown firmware initialisation error %02x:%02x:%02x\n", error, param1, param2); 3044da8bb3a3SMike Smith break; 3045da8bb3a3SMike Smith } 3046da8bb3a3SMike Smith return(0); 3047da8bb3a3SMike Smith } 3048da8bb3a3SMike Smith 30491ac4b82bSMike Smith /******************************************************************************** 30501ac4b82bSMike Smith ******************************************************************************** 30511ac4b82bSMike Smith Utility Functions 30521ac4b82bSMike Smith ******************************************************************************** 30531ac4b82bSMike Smith ********************************************************************************/ 30541ac4b82bSMike Smith 30551ac4b82bSMike Smith /******************************************************************************** 30561ac4b82bSMike Smith * Find the disk whose unit number is (unit) on this controller 30571ac4b82bSMike Smith */ 30581ac4b82bSMike Smith static struct mlx_sysdrive * 30591ac4b82bSMike Smith mlx_findunit(struct mlx_softc *sc, int unit) 30601ac4b82bSMike Smith { 30611ac4b82bSMike Smith int i; 30621ac4b82bSMike Smith 30631ac4b82bSMike Smith /* search system drives */ 30640fca6f8bSJohn Baldwin MLX_CONFIG_ASSERT_LOCKED(sc); 30651ac4b82bSMike Smith for (i = 0; i < MLX_MAXDRIVES; i++) { 30661ac4b82bSMike Smith /* is this one attached? */ 30671ac4b82bSMike Smith if (sc->mlx_sysdrive[i].ms_disk != 0) { 30681ac4b82bSMike Smith /* is this the one? */ 30691ac4b82bSMike Smith if (unit == device_get_unit(sc->mlx_sysdrive[i].ms_disk)) 30701ac4b82bSMike Smith return(&sc->mlx_sysdrive[i]); 30711ac4b82bSMike Smith } 30721ac4b82bSMike Smith } 30731ac4b82bSMike Smith return(NULL); 30741ac4b82bSMike Smith } 3075