This is a driver for the Mylex DAC960 family of integrated RAID

controllers.  It currently supports the P, PL, PD and PU variants,
with more to be supported shortly.
This commit is contained in:
Mike Smith 1999-10-07 02:20:32 +00:00
parent 5c0b893d05
commit 1ac4b82b11
7 changed files with 3459 additions and 0 deletions

2295
sys/dev/mlx/mlx.c Normal file

File diff suppressed because it is too large Load Diff

314
sys/dev/mlx/mlx_disk.c Normal file
View File

@ -0,0 +1,314 @@
/*-
* Copyright (c) 1999 Jonathan Lemon
* Copyright (c) 1999 Michael Smith
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
/*
* Disk driver for Mylex DAC960 RAID adapters.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/buf.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/devicestat.h>
#include <sys/disk.h>
#include <machine/bus.h>
#include <machine/clock.h>
#include <sys/rman.h>
#include <dev/mlx/mlxio.h>
#include <dev/mlx/mlxvar.h>
#if 0
#define debug(fmt, args...) printf("%s: " fmt "\n", __FUNCTION__ , ##args)
#else
#define debug(fmt, args...)
#endif
/* prototypes */
static int mlxd_probe(device_t dev);
static int mlxd_attach(device_t dev);
static int mlxd_detach(device_t dev);
static d_open_t mlxd_open;
static d_close_t mlxd_close;
static d_strategy_t mlxd_strategy;
static d_ioctl_t mlxd_ioctl;
#define MLXD_BDEV_MAJOR 27
#define MLXD_CDEV_MAJOR 131
static struct cdevsw mlxd_cdevsw = {
/* open */ mlxd_open,
/* close */ mlxd_close,
/* read */ physread,
/* write */ physwrite,
/* ioctl */ mlxd_ioctl,
/* poll */ nopoll,
/* mmap */ nommap,
/* strategy */ mlxd_strategy,
/* name */ "mlxd",
/* maj */ MLXD_CDEV_MAJOR,
/* dump */ nodump,
/* psize */ nopsize,
/* flags */ D_DISK,
/* bmaj */ MLXD_BDEV_MAJOR
};
static devclass_t mlxd_devclass;
static struct cdevsw mlxddisk_cdevsw;
static int disks_registered = 0;
static device_method_t mlxd_methods[] = {
DEVMETHOD(device_probe, mlxd_probe),
DEVMETHOD(device_attach, mlxd_attach),
DEVMETHOD(device_detach, mlxd_detach),
{ 0, 0 }
};
static driver_t mlxd_driver = {
"mlxd",
mlxd_methods,
sizeof(struct mlxd_softc)
};
DRIVER_MODULE(mlxd, mlx, mlxd_driver, mlxd_devclass, 0, 0);
static __inline struct mlxd_softc *
mlxd_getsoftc(dev_t dev)
{
int unit;
unit = dkunit(dev);
return ((struct mlxd_softc *)devclass_get_softc(mlxd_devclass, unit));
}
static int
mlxd_open(dev_t dev, int flags, int fmt, struct proc *p)
{
struct mlxd_softc *sc = mlxd_getsoftc(dev);
struct disklabel *label;
debug("called");
if (sc == NULL)
return (ENXIO);
/* controller not active? */
if (sc->mlxd_controller->mlx_state & MLX_STATE_SHUTDOWN)
return(ENXIO);
label = &sc->mlxd_disk.d_label;
bzero(label, sizeof(*label));
label->d_type = DTYPE_SCSI;
label->d_secsize = MLX_BLKSIZE;
label->d_nsectors = sc->mlxd_drive->ms_sectors;
label->d_ntracks = sc->mlxd_drive->ms_heads;
label->d_ncylinders = sc->mlxd_drive->ms_cylinders;
label->d_secpercyl = sc->mlxd_drive->ms_sectors * sc->mlxd_drive->ms_heads;
label->d_secperunit = sc->mlxd_drive->ms_size;
/* set maximum I/O size */
dev->si_iosize_max = sc->mlxd_controller->mlx_maxiosize;
sc->mlxd_flags |= MLXD_OPEN;
return (0);
}
static int
mlxd_close(dev_t dev, int flags, int fmt, struct proc *p)
{
struct mlxd_softc *sc = mlxd_getsoftc(dev);
debug("called");
if (sc == NULL)
return (ENXIO);
sc->mlxd_flags &= ~MLXD_OPEN;
return (0);
}
static int
mlxd_ioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p)
{
struct mlxd_softc *sc = mlxd_getsoftc(dev);
int error;
debug("called");
if (sc == NULL)
return (ENXIO);
if ((error = mlx_submit_ioctl(sc->mlxd_controller, sc->mlxd_drive, cmd, addr, flag, p)) != ENOIOCTL) {
debug("mlx_submit_ioctl returned %d\n", error);
return(error);
}
return (ENOTTY);
}
/*
* Read/write routine for a buffer. Finds the proper unit, range checks
* arguments, and schedules the transfer. Does not wait for the transfer
* to complete. Multi-page transfers are supported. All I/O requests must
* be a multiple of a sector in length.
*/
static void
mlxd_strategy(struct buf *bp)
{
struct mlxd_softc *sc = mlxd_getsoftc(bp->b_dev);
int s;
debug("called");
/* bogus disk? */
if (sc == NULL) {
bp->b_error = EINVAL;
goto bad;
}
/* XXX may only be temporarily offline - sleep? */
if (sc->mlxd_drive->ms_state == MLX_SYSD_OFFLINE) {
bp->b_error = ENXIO;
goto bad;
}
/* do-nothing operation */
if (bp->b_bcount == 0)
goto done;
/* pass reference to us */
bp->b_driver1 = sc;
s = splbio();
devstat_start_transaction(&sc->mlxd_stats);
mlx_submit_buf(sc->mlxd_controller, bp);
splx(s);
return;
bad:
bp->b_flags |= B_ERROR;
done:
/*
* Correctly set the buf to indicate a completed transfer
*/
bp->b_resid = bp->b_bcount;
biodone(bp);
return;
}
void
mlxd_intr(void *data)
{
struct buf *bp = (struct buf *)data;
struct mlxd_softc *sc = (struct mlxd_softc *)bp->b_driver1;
debug("called");
if (bp->b_flags & B_ERROR)
bp->b_error = EIO;
else
bp->b_resid = 0;
devstat_end_transaction_buf(&sc->mlxd_stats, bp);
biodone(bp);
}
static int
mlxd_probe(device_t dev)
{
debug("called");
device_set_desc(dev, "Mylex System Drive");
return (0);
}
static int
mlxd_attach(device_t dev)
{
struct mlxd_softc *sc = (struct mlxd_softc *)device_get_softc(dev);
device_t parent;
char *state;
debug("called");
parent = device_get_parent(dev);
sc->mlxd_controller = (struct mlx_softc *)device_get_softc(parent);
sc->mlxd_unit = device_get_unit(dev);
sc->mlxd_drive = device_get_ivars(dev);
switch(sc->mlxd_drive->ms_state) {
case MLX_SYSD_ONLINE:
state = "online";
break;
case MLX_SYSD_CRITICAL:
state = "critical";
break;
case MLX_SYSD_OFFLINE:
state = "offline";
break;
default:
state = "unknown state";
}
device_printf(dev, "%uMB (%u sectors), RAID %d (%s)\n",
sc->mlxd_drive->ms_size / ((1024 * 1024) / MLX_BLKSIZE),
sc->mlxd_drive->ms_size, sc->mlxd_drive->ms_raidlevel, state);
devstat_add_entry(&sc->mlxd_stats, "mlxd", sc->mlxd_unit, MLX_BLKSIZE,
DEVSTAT_NO_ORDERED_TAGS,
DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_OTHER,
DEVSTAT_PRIORITY_DA);
disk_create(sc->mlxd_unit, &sc->mlxd_disk, 0, &mlxd_cdevsw, &mlxddisk_cdevsw);
disks_registered++;
return (0);
}
static int
mlxd_detach(device_t dev)
{
struct mlxd_softc *sc = (struct mlxd_softc *)device_get_softc(dev);
debug("called");
devstat_remove_entry(&sc->mlxd_stats);
/* hack to handle lack of destroy_disk() */
if (--disks_registered == 0)
cdevsw_remove(&mlxddisk_cdevsw);
return(0);
}

199
sys/dev/mlx/mlx_pci.c Normal file
View File

@ -0,0 +1,199 @@
/*-
* Copyright (c) 1999 Michael Smith
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/buf.h>
#include <sys/conf.h>
#include <sys/devicestat.h>
#include <sys/disk.h>
#include <machine/bus_memio.h>
#include <machine/bus_pio.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <sys/rman.h>
#include <pci/pcireg.h>
#include <pci/pcivar.h>
#include <dev/mlx/mlxio.h>
#include <dev/mlx/mlxvar.h>
#if 0
#define debug(fmt, args...) printf("%s: " fmt "\n", __FUNCTION__ , ##args)
#else
#define debug(fmt, args...)
#endif
static int mlx_pci_probe(device_t dev);
static int mlx_pci_attach(device_t dev);
static device_method_t mlx_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, mlx_pci_probe),
DEVMETHOD(device_attach, mlx_pci_attach),
DEVMETHOD(device_detach, mlx_detach),
DEVMETHOD(device_shutdown, mlx_shutdown),
DEVMETHOD(device_suspend, mlx_suspend),
DEVMETHOD(device_resume, mlx_resume),
DEVMETHOD(bus_print_child, bus_generic_print_child),
DEVMETHOD(bus_driver_added, bus_generic_driver_added),
{ 0, 0 }
};
static driver_t mlx_pci_driver = {
"mlx",
mlx_methods,
sizeof(struct mlx_softc)
};
DRIVER_MODULE(mlx, pci, mlx_pci_driver, mlx_devclass, 0, 0);
struct
{
u_int16_t vendor;
u_int16_t device;
int iftype;
char *desc;
} mlx_identifiers[] = {
{0x1069, 0x0002, MLX_IFTYPE_3, "Mylex version 3 RAID interface"}, /* Mylex v3 software interface */
{0, 0, 0, 0}
};
static int
mlx_pci_probe(device_t dev)
{
int i;
debug("called");
for (i = 0; mlx_identifiers[i].vendor != 0; i++) {
if ((mlx_identifiers[i].vendor == pci_get_vendor(dev)) &&
(mlx_identifiers[i].device == pci_get_device(dev))) {
device_set_desc(dev, mlx_identifiers[i].desc);
return(0);
}
}
return(ENXIO);
}
static int
mlx_pci_attach(device_t dev)
{
struct mlx_softc *sc;
int i, rid, error;
u_int32_t command;
debug("called");
/*
* Make sure we are going to be able to talk to this board.
*/
command = pci_read_config(dev, PCIR_COMMAND, 1);
if ((command & PCIM_CMD_MEMEN) == 0) {
device_printf(dev, "memory window not available\n");
return(ENXIO);
}
/*
* Initialise softc.
*/
sc = device_get_softc(dev);
bzero(sc, sizeof(*sc));
sc->mlx_dev = dev;
/*
* Work out what sort of adapter this is (we need to know this in order
* to map the appropriate interface resources).
*/
sc->mlx_iftype = 0;
for (i = 0; mlx_identifiers[i].vendor != 0; i++) {
if ((mlx_identifiers[i].vendor == pci_get_vendor(dev)) &&
(mlx_identifiers[i].device == pci_get_device(dev))) {
sc->mlx_iftype = mlx_identifiers[i].iftype;
break;
}
}
if (sc->mlx_iftype == 0) /* shouldn't happen */
return(ENXIO);
/*
* Allocate the PCI register window.
*/
/* type 3 adapters have an I/O region we don't use at base 0 */
rid = (sc->mlx_iftype == MLX_IFTYPE_3) ? MLX_CFG_BASE1 : MLX_CFG_BASE0;
sc->mlx_mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0, 1, RF_ACTIVE);
if (sc->mlx_mem == NULL) {
device_printf(sc->mlx_dev, "couldn't allocate mailbox window\n");
mlx_free(sc);
return(ENXIO);
}
sc->mlx_btag = rman_get_bustag(sc->mlx_mem);
sc->mlx_bhandle = rman_get_bushandle(sc->mlx_mem);
/*
* Allocate the parent bus DMA tag appropriate for PCI.
*/
error = bus_dma_tag_create(NULL, /* parent */
1, 0, /* alignment, boundary */
BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
BUS_SPACE_MAXADDR, /* highaddr */
NULL, NULL, /* filter, filterarg */
MAXBSIZE, MLX_NSEG, /* maxsize, nsegments */
BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
BUS_DMA_ALLOCNOW, /* flags */
&sc->mlx_parent_dmat);
if (error != 0) {
device_printf(dev, "can't allocate parent DMA tag\n");
mlx_free(sc);
return(ENOMEM);
}
/*
* Do bus-independant initialisation.
*/
error = mlx_attach(sc);
if (error != 0) {
mlx_free(sc);
return(error);
}
/*
* Start the controller.
*/
mlx_startup(sc);
return(0);
}

88
sys/dev/mlx/mlxio.h Normal file
View File

@ -0,0 +1,88 @@
/*-
* Copyright (c) 1999 Michael Smith
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <sys/ioccom.h>
/*
* System Disk ioctls
*/
struct mlxd_rebuild
{
int rb_channel;
int rb_target;
};
struct mlxd_rebuild_status
{
int rs_drive;
int rs_size;
int rs_remaining;
};
#define MLXD_STATUS _IOR ('M', 100, int)
#define MLXD_REBUILDASYNC _IOW ('M', 101, struct mlxd_rebuild)
#define MLXD_CHECKASYNC _IOW ('M', 102, int)
#define MLXD_REBUILDSTAT _IOR ('M', 103, struct mlxd_rebuild_status)
/*
* System Disk status values
*/
#define MLX_SYSD_ONLINE 0x03
#define MLX_SYSD_CRITICAL 0x04
#define MLX_SYSD_REBUILD 0xfe
#define MLX_SYSD_OFFLINE 0xff
/*
* Controller ioctls
*/
struct mlx_pause
{
int mp_which;
#define MLX_PAUSE_ALL 0xff
#define MLX_PAUSE_CANCEL 0x00
int mp_when;
int mp_howlong;
};
struct mlx_usercommand
{
/* data buffer */
size_t mu_datasize; /* size of databuffer */
void *mu_buf; /* address in userspace of databuffer */
int mu_bufptr; /* offset into command mailbox to place databuffer address */
/* command */
u_int16_t mu_status; /* command status returned */
u_int8_t mu_command[16]; /* command mailbox contents */
};
#define MLX_NEXT_CHILD _IOWR('M', 0, int)
#define MLX_RESCAN_DRIVES _IO ('M', 1)
#define MLX_DETACH_DRIVE _IOW ('M', 2, int)
#define MLX_PAUSE_CHANNEL _IOW ('M', 3, struct mlx_pause)
#define MLX_COMMAND _IOWR('M', 4, struct mlx_usercommand)

188
sys/dev/mlx/mlxreg.h Normal file
View File

@ -0,0 +1,188 @@
/*-
* Copyright (c) 1999 Michael Smith
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
/*
* Selected command codes.
*/
#define MLX_CMD_ENQUIRY 0x53
#define MLX_CMD_ENQUIRY2 0x1c
#define MLX_CMD_ENQSYSDRIVE 0x19
#define MLX_CMD_READOLDSG 0xb6
#define MLX_CMD_WRITEOLDSG 0xb7
#define MLX_CMD_FLUSH 0x0a
#define MLX_CMD_LOGOP 0x72
#define MLX_CMD_REBUILDASYNC 0x16
#define MLX_CMD_CHECKASYNC 0x1e
#define MLX_CMD_REBUILDSTAT 0x0c
#define MLX_CMD_STOPCHANNEL 0x13
#define MLX_CMD_STARTCHANNEL 0x12
/*
* Status values.
*/
#define MLX_STATUS_OK 0x0000
#define MLX_STATUS_RDWROFFLINE 0x0002 /* read/write claims drive is offline */
#define MLX_STATUS_WEDGED 0xdead /* controller not listening */
#define MLX_STATUS_BUSY 0xffff /* command is in controller */
/*
* Scatter-gather list format, type 1, kind 00.
*/
struct mlx_sgentry
{
u_int32_t sg_addr;
u_int32_t sg_count;
} __attribute__ ((packed));
/*
* Command result buffers, as placed in system memory by the controller.
*/
struct mlx_enquiry /* MLX_CMD_ENQUIRY */
{
u_int8_t me_num_sys_drvs;
u_int8_t res1[3];
u_int32_t me_drvsize[32];
u_int16_t me_flash_age;
u_int8_t me_status_flags;
#define MLX_ENQ_SFLAG_DEFWRERR (1<<0) /* deferred write error indicator */
#define MLX_ENQ_SFLAG_BATTLOW (1<<1) /* battery low */
u_int8_t res2;
u_int8_t me_fwminor;
u_int8_t me_fwmajor;
u_int8_t me_rebuild_flag;
u_int8_t me_max_commands;
u_int8_t me_offline_sd_count;
u_int8_t res3;
u_int16_t me_event_log_seq_num;
u_int8_t me_critical_sd_count;
u_int8_t res4[3];
u_int8_t me_dead_count;
u_int8_t res5;
u_int8_t me_rebuild_count;
u_int8_t me_misc_flags;
#define MLX_ENQ_MISC_BBU (1<<3) /* battery backup present */
struct
{
u_int8_t dd_targ;
u_int8_t dd_chan;
} __attribute__ ((packed)) me_dead[20];
} __attribute__ ((packed));
struct mlx_enquiry2 /* MLX_CMD_ENQUIRY2 */
{
u_int32_t me_hardware_id;
u_int32_t me_firmware_id;
u_int32_t res1;
u_int8_t me_configured_channels;
u_int8_t me_actual_channels;
u_int8_t me_max_targets;
u_int8_t me_max_tags;
u_int8_t me_max_sys_drives;
u_int8_t me_max_arms;
u_int8_t me_max_spans;
u_int8_t res2;
u_int32_t res3;
u_int32_t me_mem_size;
u_int32_t me_cache_size;
u_int32_t me_flash_size;
u_int32_t me_nvram_size;
u_int16_t me_mem_type;
u_int16_t me_clock_speed;
u_int16_t me_mem_speed;
u_int16_t me_hardware_speed;
u_int8_t res4[10];
u_int16_t me_max_commands;
u_int16_t me_max_sg;
u_int16_t me_max_dp;
u_int16_t me_max_iod;
u_int16_t me_max_comb;
u_int8_t me_latency;
u_int8_t res5;
u_int8_t me_scsi_timeout;
u_int8_t res6;
u_int16_t me_min_freelines;
u_int8_t res7[8];
u_int8_t me_rate_const;
u_int8_t res8[11];
u_int16_t me_physblk;
u_int16_t me_logblk;
u_int16_t me_maxblk;
u_int16_t me_blocking_factor;
u_int16_t me_cacheline;
u_int8_t me_scsi_cap;
u_int8_t res9[5];
u_int16_t me_fimware_build;
u_int8_t me_fault_mgmt_type;
u_int8_t res10;
u_int32_t me_firmware_features;
u_int8_t res11[8];
} __attribute__ ((packed));
struct mlx_enq_sys_drive /* MLX_CMD_ENQSYSDRIVE returns an array of 32 of these */
{
u_int32_t sd_size;
u_int8_t sd_state;
u_int8_t sd_raidlevel;
u_int16_t res1;
} __attribute__ ((packed));
struct mlx_eventlog_entry /* MLX_CMD_LOGOP/MLX_LOGOP_GET */
{
u_int8_t el_type;
u_int8_t el_length;
u_char el_target:5;
u_char el_channel:3;
u_char el_lun:6;
u_char res1:2;
u_int16_t el_seqno;
u_char el_errorcode:7;
u_char el_valid:1;
u_int8_t el_segment;
u_char el_sensekey:4;
u_char res2:1;
u_char el_ILI:1;
u_char el_EOM:1;
u_char el_filemark:1;
u_int8_t el_information[4];
u_int8_t el_addsense;
u_int8_t el_csi[4];
u_int8_t el_asc;
u_int8_t el_asq;
u_int8_t res3[12];
} __attribute__ ((packed));
#define MLX_LOGOP_GET 0x00 /* operation codes for MLX_CMD_LOGOP */
#define MLX_LOGMSG_SENSE 0x00 /* log message contents codes */
struct mlx_rebuild_stat /* MLX_CMD_REBUILDSTAT */
{
u_int32_t rb_drive;
u_int32_t rb_size;
u_int32_t rb_remaining;
} __attribute__ ((packed));

353
sys/dev/mlx/mlxvar.h Normal file
View File

@ -0,0 +1,353 @@
/*-
* Copyright (c) 1999 Michael Smith
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
/*
* We could actually use all 33 segments, but using only 32 means that
* each scatter/gather map is 256 bytes in size, and thus we don't have to worry about
* maps crossing page boundaries.
*/
#define MLX_NSEG 32 /* max scatter/gather segments we use */
#define MLX_NSLOTS 256 /* max number of command slots */
#define MLX_CFG_BASE0 0x10 /* first region */
#define MLX_CFG_BASE1 0x14 /* second region (type 3 only) */
#define MLX_MAXDRIVES 32
#define MLX_BLKSIZE 512 /* fixed feature */
/*
* Structure describing a System Drive as attached to the controller.
*/
struct mlx_sysdrive
{
/* from MLX_CMD_ENQSYSDRIVE */
u_int32_t ms_size;
int ms_state;
int ms_raidlevel;
/* synthetic geometry */
int ms_cylinders;
int ms_heads;
int ms_sectors;
/* handle for attached driver */
device_t ms_disk;
};
/*
* Per-command control structure.
*/
struct mlx_command
{
TAILQ_ENTRY(mlx_command) mc_link; /* list linkage */
struct mlx_softc *mc_sc; /* controller that owns us */
u_int8_t mc_slot; /* command slot we occupy */
u_int16_t mc_status; /* command completion status */
u_int8_t mc_mailbox[16]; /* command mailbox */
u_int32_t mc_sgphys; /* physical address of s/g array in controller space */
int mc_nsgent; /* number of entries in s/g map */
int mc_flags;
#define MLX_CMD_DATAIN (1<<0)
#define MLX_CMD_DATAOUT (1<<1)
#define MLX_CMD_PRIORITY (1<<2) /* high-priority command */
void *mc_data; /* data buffer */
size_t mc_length;
bus_dmamap_t mc_dmamap; /* DMA map for data */
u_int32_t mc_dataphys; /* data buffer base address controller space */
void (* mc_complete)(struct mlx_command *mc); /* completion handler */
void *mc_private; /* submitter-private data or wait channel */
};
/*
* Per-controller structure.
*/
struct mlx_softc
{
/* bus connections */
device_t mlx_dev;
struct resource *mlx_mem; /* mailbox interface window */
bus_space_handle_t mlx_bhandle; /* bus space handle */
bus_space_tag_t mlx_btag; /* bus space tag */
bus_dma_tag_t mlx_parent_dmat;/* parent DMA tag */
bus_dma_tag_t mlx_buffer_dmat;/* data buffer DMA tag */
struct resource *mlx_irq; /* interrupt */
void *mlx_intr; /* interrupt handle */
/* scatter/gather lists and their controller-visible mappings */
struct mlx_sgentry *mlx_sgtable; /* s/g lists */
u_int32_t mlx_sgbusaddr; /* s/g table base address in bus space */
bus_dma_tag_t mlx_sg_dmat; /* s/g buffer DMA tag */
bus_dmamap_t mlx_sg_dmamap; /* map for s/g buffers */
/* controller limits and features */
int mlx_hwid; /* hardware identifier */
int mlx_maxiop; /* maximum number of I/O operations */
int mlx_nchan; /* number of active channels */
int mlx_maxiosize; /* largest I/O for this controller */
int mlx_maxtarg; /* maximum number of targets per channel */
int mlx_maxtags; /* maximum number of tags per device */
int mlx_scsicap; /* SCSI capabilities */
int mlx_feature; /* controller features/quirks */
#define MLX_FEAT_PAUSEWORKS (1<<0) /* channel pause works as expected */
/* controller queues and arrays */
TAILQ_HEAD(, mlx_command) mlx_freecmds; /* command structures available for reuse */
TAILQ_HEAD(, mlx_command) mlx_donecmd; /* commands waiting for completion processing */
struct mlx_command *mlx_busycmd[MLX_NSLOTS]; /* busy commands */
int mlx_busycmds; /* count of busy commands */
struct mlx_sysdrive mlx_sysdrive[MLX_MAXDRIVES]; /* system drives */
struct buf_queue_head mlx_bufq; /* outstanding I/O operations */
int mlx_waitbufs; /* number of bufs awaiting commands */
/* controller status */
u_int8_t mlx_fwminor; /* firmware revision */
u_int8_t mlx_fwmajor;
int mlx_geom;
#define MLX_GEOM_128_32 0 /* geoemetry translation modes */
#define MLX_GEOM_256_63 1
int mlx_state;
#define MLX_STATE_INTEN (1<<0) /* interrupts have been enabled */
#define MLX_STATE_SHUTDOWN (1<<1) /* controller is shut down */
#define MLX_STATE_OPEN (1<<2) /* control device is open */
#define MLX_STATE_SUSPEND (1<<3) /* controller is suspended */
struct callout_handle mlx_timeout; /* periodic status monitor */
time_t mlx_lastpoll; /* last time_second we polled for status */
u_int16_t mlx_lastevent; /* sequence number of the last event we recorded */
u_int16_t mlx_currevent; /* sequence number last time we looked */
int mlx_polling; /* if > 0, polling operations still running */
int mlx_rebuild; /* if >= 0, drive is being rebuilt */
u_int32_t mlx_rebuildstat;/* blocks left to rebuild if active */
int mlx_check; /* if >= 0, drive is being checked */
struct mlx_pause mlx_pause; /* pending pause operation details */
/* interface-specific accessor functions */
int mlx_iftype; /* interface protocol */
#define MLX_IFTYPE_3 3
#define MLX_IFTYPE_4 4
#define MLX_IFTYPE_5 5
int (* mlx_tryqueue)(struct mlx_softc *sc, struct mlx_command *mc);
int (* mlx_findcomplete)(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status);
void (* mlx_intaction)(struct mlx_softc *sc, int action);
#define MLX_INTACTION_DISABLE 0
#define MLX_INTACTION_ENABLE 1
#define MLX_INTACTION_ACKNOWLEDGE 2
};
/*
* Interface between bus connections and driver core.
*/
extern void mlx_free(struct mlx_softc *sc);
extern int mlx_attach(struct mlx_softc *sc);
extern void mlx_startup(struct mlx_softc *sc);
extern void mlx_intr(void *data);
extern int mlx_detach(device_t dev);
extern int mlx_shutdown(device_t dev);
extern int mlx_suspend(device_t dev);
extern int mlx_resume(device_t dev);
extern d_open_t mlx_open;
extern d_close_t mlx_close;
extern d_ioctl_t mlx_ioctl;
extern devclass_t mlx_devclass;
/*
* Mylex System Disk driver
*/
struct mlxd_softc
{
device_t mlxd_dev;
struct mlx_softc *mlxd_controller;
struct mlx_sysdrive *mlxd_drive;
struct disk mlxd_disk;
struct devstat mlxd_stats;
struct disklabel mlxd_label;
int mlxd_unit;
int mlxd_flags;
#define MLXD_OPEN (1<<0) /* drive is open (can't shut down) */
};
/*
* Interface between driver core and disk driver (should be using a bus?)
*/
extern int mlx_submit_buf(struct mlx_softc *sc, struct buf *bp);
extern int mlx_submit_ioctl(struct mlx_softc *sc, struct mlx_sysdrive *drive, u_long cmd,
caddr_t addr, int32_t flag, struct proc *p);
extern void mlxd_intr(void *data);
/*
* Accessor defines for the V3 interface.
*/
#define MLX_V3_MAILBOX 0x00
#define MLX_V3_STATUS_IDENT 0x0d
#define MLX_V3_STATUS 0x0e
#define MLX_V3_IDBR 0x40
#define MLX_V3_ODBR 0x41
#define MLX_V3_IER 0x43
#define MLX_V3_PUT_MAILBOX(sc, idx, val) bus_space_write_1(sc->mlx_btag, sc->mlx_bhandle, MLX_V3_MAILBOX + idx, val)
#define MLX_V3_GET_STATUS_IDENT(sc) bus_space_read_1 (sc->mlx_btag, sc->mlx_bhandle, MLX_V3_STATUS_IDENT)
#define MLX_V3_GET_STATUS(sc) bus_space_read_2 (sc->mlx_btag, sc->mlx_bhandle, MLX_V3_STATUS)
#define MLX_V3_GET_IDBR(sc) bus_space_read_1 (sc->mlx_btag, sc->mlx_bhandle, MLX_V3_IDBR)
#define MLX_V3_PUT_IDBR(sc, val) bus_space_write_1(sc->mlx_btag, sc->mlx_bhandle, MLX_V3_IDBR, val)
#define MLX_V3_GET_ODBR(sc) bus_space_read_1 (sc->mlx_btag, sc->mlx_bhandle, MLX_V3_ODBR)
#define MLX_V3_PUT_ODBR(sc, val) bus_space_write_1(sc->mlx_btag, sc->mlx_bhandle, MLX_V3_ODBR, val)
#define MLX_V3_PUT_IER(sc, val) bus_space_write_1(sc->mlx_btag, sc->mlx_bhandle, MLX_V3_IER, val)
#define MLX_V3_IDB_FULL (1<<0) /* mailbox is full */
#define MLX_V3_IDB_SACK (1<<1) /* acknowledge status read */
#define MLX_V3_IDB_RESET (1<<3) /* request soft reset */
#define MLX_V3_ODB_SAVAIL (1<<0) /* status is available */
/*
* Inlines to build various command structures
*/
static __inline void
mlx_make_type1(struct mlx_command *mc,
u_int8_t code,
u_int16_t f1,
u_int32_t f2,
u_int8_t f3,
u_int32_t f4,
u_int8_t f5)
{
mc->mc_mailbox[0x0] = code;
mc->mc_mailbox[0x2] = f1 & 0xff;
mc->mc_mailbox[0x3] = (((f2 >> 24) & 0x3) << 6) | ((f1 >> 8) & 0x3f);
mc->mc_mailbox[0x4] = f2 & 0xff;
mc->mc_mailbox[0x5] = (f2 >> 8) & 0xff;
mc->mc_mailbox[0x6] = (f2 >> 16) & 0xff;
mc->mc_mailbox[0x7] = f3;
mc->mc_mailbox[0x8] = f4 & 0xff;
mc->mc_mailbox[0x9] = (f4 >> 8) & 0xff;
mc->mc_mailbox[0xa] = (f4 >> 16) & 0xff;
mc->mc_mailbox[0xb] = (f4 >> 24) & 0xff;
mc->mc_mailbox[0xc] = f5;
}
static __inline void
mlx_make_type2(struct mlx_command *mc,
u_int8_t code,
u_int8_t f1,
u_int8_t f2,
u_int8_t f3,
u_int8_t f4,
u_int8_t f5,
u_int8_t f6,
u_int32_t f7,
u_int8_t f8)
{
mc->mc_mailbox[0x0] = code;
mc->mc_mailbox[0x2] = f1;
mc->mc_mailbox[0x3] = f2;
mc->mc_mailbox[0x4] = f3;
mc->mc_mailbox[0x5] = f4;
mc->mc_mailbox[0x6] = f5;
mc->mc_mailbox[0x7] = f6;
mc->mc_mailbox[0x8] = f7 & 0xff;
mc->mc_mailbox[0x9] = (f7 >> 8) & 0xff;
mc->mc_mailbox[0xa] = (f7 >> 16) & 0xff;
mc->mc_mailbox[0xb] = (f7 >> 24) & 0xff;
mc->mc_mailbox[0xc] = f8;
}
static __inline void
mlx_make_type3(struct mlx_command *mc,
u_int8_t code,
u_int8_t f1,
u_int8_t f2,
u_int16_t f3,
u_int8_t f4,
u_int8_t f5,
u_int32_t f6,
u_int8_t f7)
{
mc->mc_mailbox[0x0] = code;
mc->mc_mailbox[0x2] = f1;
mc->mc_mailbox[0x3] = f2;
mc->mc_mailbox[0x4] = f3 & 0xff;
mc->mc_mailbox[0x5] = (f3 >> 8) & 0xff;
mc->mc_mailbox[0x6] = f4;
mc->mc_mailbox[0x7] = f5;
mc->mc_mailbox[0x8] = f6 & 0xff;
mc->mc_mailbox[0x9] = (f6 >> 8) & 0xff;
mc->mc_mailbox[0xa] = (f6 >> 16) & 0xff;
mc->mc_mailbox[0xb] = (f6 >> 24) & 0xff;
mc->mc_mailbox[0xc] = f7;
}
static __inline void
mlx_make_type4(struct mlx_command *mc,
u_int8_t code,
u_int16_t f1,
u_int32_t f2,
u_int32_t f3,
u_int8_t f4)
{
mc->mc_mailbox[0x0] = code;
mc->mc_mailbox[0x2] = f1 & 0xff;
mc->mc_mailbox[0x3] = (f1 >> 8) & 0xff;
mc->mc_mailbox[0x4] = f2 & 0xff;
mc->mc_mailbox[0x5] = (f2 >> 8) & 0xff;
mc->mc_mailbox[0x6] = (f2 >> 16) & 0xff;
mc->mc_mailbox[0x7] = (f2 >> 24) & 0xff;
mc->mc_mailbox[0x8] = f3 & 0xff;
mc->mc_mailbox[0x9] = (f3 >> 8) & 0xff;
mc->mc_mailbox[0xa] = (f3 >> 16) & 0xff;
mc->mc_mailbox[0xb] = (f3 >> 24) & 0xff;
mc->mc_mailbox[0xc] = f4;
}
static __inline void
mlx_make_type5(struct mlx_command *mc,
u_int8_t code,
u_int8_t f1,
u_int8_t f2,
u_int32_t f3,
u_int32_t f4,
u_int8_t f5)
{
mc->mc_mailbox[0x0] = code;
mc->mc_mailbox[0x2] = f1;
mc->mc_mailbox[0x3] = f2;
mc->mc_mailbox[0x4] = f3 & 0xff;
mc->mc_mailbox[0x5] = (f3 >> 8) & 0xff;
mc->mc_mailbox[0x6] = (f3 >> 16) & 0xff;
mc->mc_mailbox[0x7] = (f3 >> 24) & 0xff;
mc->mc_mailbox[0x8] = f4 & 0xff;
mc->mc_mailbox[0x9] = (f4 >> 8) & 0xff;
mc->mc_mailbox[0xa] = (f4 >> 16) & 0xff;
mc->mc_mailbox[0xb] = (f4 >> 24) & 0xff;
mc->mc_mailbox[0xc] = f5;
}

22
sys/modules/mlx/Makefile Normal file
View File

@ -0,0 +1,22 @@
# $FreeBSD$
S = ${.CURDIR}/../..
.PATH: $S/dev/mlx
KMOD = mlx
SRCS = mlx.c mlx_pci.c mlx_disk.c device_if.h bus_if.h pci_if.h
CLEANFILES += mlx.h device_if.h bus_if.h pci_if.h
CFLAGS += ${DEBUG_FLAGS}
mlx.h:
echo "#define NMLX 1" > mlx.h
device_if.h: $S/kern/makedevops.pl $S/kern/device_if.m
perl $S/kern/makedevops.pl -h $S/kern/device_if.m
bus_if.h: $S/kern/makedevops.pl $S/kern/bus_if.m
perl $S/kern/makedevops.pl -h $S/kern/bus_if.m
pci_if.h: $S/kern/makedevops.pl $S/pci/pci_if.m
perl $S/kern/makedevops.pl -h $S/pci/pci_if.m
.include <bsd.kmod.mk>