summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/mlx/mlx.c562
-rw-r--r--sys/dev/mlx/mlx_disk.c24
-rw-r--r--sys/dev/mlx/mlx_pci.c32
-rw-r--r--sys/dev/mlx/mlxio.h5
-rw-r--r--sys/dev/mlx/mlxreg.h213
-rw-r--r--sys/dev/mlx/mlxvar.h30
6 files changed, 704 insertions, 162 deletions
diff --git a/sys/dev/mlx/mlx.c b/sys/dev/mlx/mlx.c
index 8760ccd..3e33bfa 100644
--- a/sys/dev/mlx/mlx.c
+++ b/sys/dev/mlx/mlx.c
@@ -40,6 +40,7 @@
#include <sys/conf.h>
#include <sys/devicestat.h>
#include <sys/disk.h>
+#include <sys/stat.h>
#include <machine/resource.h>
#include <machine/bus.h>
@@ -50,12 +51,6 @@
#include <dev/mlx/mlxvar.h>
#include <dev/mlx/mlxreg.h>
-#if 0
-#define debug(fmt, args...) printf("%s: " fmt "\n", __FUNCTION__ , ##args)
-#else
-#define debug(fmt, args...)
-#endif
-
#define MLX_CDEV_MAJOR 130
static struct cdevsw mlx_cdevsw = {
@@ -75,7 +70,6 @@ static struct cdevsw mlx_cdevsw = {
/* bmaj */ -1
};
-static int cdev_registered = 0;
devclass_t mlx_devclass;
/*
@@ -84,14 +78,17 @@ devclass_t mlx_devclass;
static int mlx_v3_tryqueue(struct mlx_softc *sc, struct mlx_command *mc);
static int mlx_v3_findcomplete(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status);
static void mlx_v3_intaction(struct mlx_softc *sc, int action);
+static int mlx_v3_fw_handshake(struct mlx_softc *sc, int *error, int *param1, int *param2);
static int mlx_v4_tryqueue(struct mlx_softc *sc, struct mlx_command *mc);
static int mlx_v4_findcomplete(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status);
static void mlx_v4_intaction(struct mlx_softc *sc, int action);
+static int mlx_v4_fw_handshake(struct mlx_softc *sc, int *error, int *param1, int *param2);
static int mlx_v5_tryqueue(struct mlx_softc *sc, struct mlx_command *mc);
static int mlx_v5_findcomplete(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status);
static void mlx_v5_intaction(struct mlx_softc *sc, int action);
+static int mlx_v5_fw_handshake(struct mlx_softc *sc, int *error, int *param1, int *param2);
/*
* Status monitoring
@@ -143,7 +140,7 @@ static void mlx_complete(struct mlx_softc *sc);
*/
static char *mlx_diagnose_command(struct mlx_command *mc);
static void mlx_describe_controller(struct mlx_softc *sc);
-
+static int mlx_fw_message(struct mlx_softc *sc, int status, int param1, int param2);
/*
* Utility functions.
@@ -166,7 +163,7 @@ mlx_free(struct mlx_softc *sc)
{
struct mlx_command *mc;
- debug("called");
+ debug_called(1);
/* cancel status timeout */
untimeout(mlx_periodic, sc, sc->mlx_timeout);
@@ -205,6 +202,10 @@ mlx_free(struct mlx_softc *sc)
/* free controller enquiry data */
if (sc->mlx_enq2 != NULL)
free(sc->mlx_enq2, M_DEVBUF);
+
+ /* destroy control device */
+ if (sc->mlx_dev_t != (dev_t)NULL)
+ destroy_dev(sc->mlx_dev_t);
}
/********************************************************************************
@@ -215,7 +216,7 @@ mlx_dma_map_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
{
struct mlx_softc *sc = (struct mlx_softc *)arg;
- debug("called");
+ debug_called(1);
/* save base of s/g table's address in bus space */
sc->mlx_sgbusaddr = segs->ds_addr;
@@ -227,7 +228,7 @@ mlx_sglist_map(struct mlx_softc *sc)
size_t segsize;
int error;
- debug("called");
+ debug_called(1);
/* destroy any existing mappings */
if (sc->mlx_sgtable)
@@ -239,7 +240,7 @@ mlx_sglist_map(struct mlx_softc *sc)
* Create a single tag describing a region large enough to hold all of
* the s/g lists we will need.
*/
- segsize = sizeof(struct mlx_sgentry) * MLX_NSEG * sc->mlx_maxiop;
+ segsize = sizeof(struct mlx_sgentry) * sc->mlx_sg_nseg * sc->mlx_maxiop;
error = bus_dma_tag_create(sc->mlx_parent_dmat, /* parent */
1, 0, /* alignment, boundary */
BUS_SPACE_MAXADDR, /* lowaddr */
@@ -277,9 +278,10 @@ mlx_sglist_map(struct mlx_softc *sc)
int
mlx_attach(struct mlx_softc *sc)
{
- int rid, error, fwminor;
+ struct mlx_enquiry_old *meo;
+ int rid, error, fwminor, hscode, hserror, hsparam1, hsparam2, hsmsg;
- debug("called");
+ debug_called(1);
/*
* Initialise per-controller queues.
@@ -292,20 +294,27 @@ mlx_attach(struct mlx_softc *sc)
* Select accessor methods based on controller interface type.
*/
switch(sc->mlx_iftype) {
+ case MLX_IFTYPE_2:
case MLX_IFTYPE_3:
sc->mlx_tryqueue = mlx_v3_tryqueue;
sc->mlx_findcomplete = mlx_v3_findcomplete;
sc->mlx_intaction = mlx_v3_intaction;
+ sc->mlx_fw_handshake = mlx_v3_fw_handshake;
+ sc->mlx_sg_nseg = MLX_NSEG_OLD;
break;
case MLX_IFTYPE_4:
sc->mlx_tryqueue = mlx_v4_tryqueue;
sc->mlx_findcomplete = mlx_v4_findcomplete;
sc->mlx_intaction = mlx_v4_intaction;
+ sc->mlx_fw_handshake = mlx_v4_fw_handshake;
+ sc->mlx_sg_nseg = MLX_NSEG_NEW;
break;
case MLX_IFTYPE_5:
sc->mlx_tryqueue = mlx_v5_tryqueue;
sc->mlx_findcomplete = mlx_v5_findcomplete;
sc->mlx_intaction = mlx_v5_intaction;
+ sc->mlx_fw_handshake = mlx_v5_fw_handshake;
+ sc->mlx_sg_nseg = MLX_NSEG_NEW;
break;
default:
device_printf(sc->mlx_dev, "attaching unsupported interface version %d\n", sc->mlx_iftype);
@@ -316,6 +325,32 @@ mlx_attach(struct mlx_softc *sc)
sc->mlx_intaction(sc, MLX_INTACTION_DISABLE);
/*
+ * Wait for the controller to come ready, handshake with the firmware if required.
+ * This is typically only necessary on platforms where the controller BIOS does not
+ * run.
+ */
+ hsmsg = 0;
+ DELAY(1000);
+ while ((hscode = sc->mlx_fw_handshake(sc, &hserror, &hsparam1, &hsparam2)) != 0) {
+ /* report first time around... */
+ if (hsmsg == 0) {
+ device_printf(sc->mlx_dev, "controller initialisation in progress...\n");
+ hsmsg = 1;
+ }
+ /* did we get a real message? */
+ if (hscode == 2) {
+ hscode = mlx_fw_message(sc, hserror, hsparam1, hsparam2);
+ /* fatal initialisation error? */
+ if (hscode != 0) {
+ mlx_free(sc);
+ return(ENXIO);
+ }
+ }
+ }
+ if (hsmsg == 1)
+ device_printf(sc->mlx_dev, "initialisation complete.\n");
+
+ /*
* Allocate and connect our interrupt.
*/
rid = 0;
@@ -335,14 +370,14 @@ mlx_attach(struct mlx_softc *sc)
/*
* Create DMA tag for mapping buffers into controller-addressable space.
*/
- error = bus_dma_tag_create(sc->mlx_parent_dmat, /* parent */
- 1, 0, /* alignment, boundary */
- BUS_SPACE_MAXADDR, /* lowaddr */
- BUS_SPACE_MAXADDR, /* highaddr */
- NULL, NULL, /* filter, filterarg */
- MAXBSIZE, MLX_NSEG, /* maxsize, nsegments */
- BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
- 0, /* flags */
+ error = bus_dma_tag_create(sc->mlx_parent_dmat, /* parent */
+ 1, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ MAXBSIZE, sc->mlx_sg_nseg, /* maxsize, nsegments */
+ BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
+ 0, /* flags */
&sc->mlx_buffer_dmat);
if (error != 0) {
device_printf(sc->mlx_dev, "can't allocate buffer DMA tag\n");
@@ -370,14 +405,26 @@ mlx_attach(struct mlx_softc *sc)
*/
sc->mlx_lastevent = -1;
- /* print a little information about the controller */
- mlx_describe_controller(sc);
-
/*
* Do quirk/feature related things.
*/
fwminor = (sc->mlx_enq2->me_firmware_id >> 8) & 0xff;
switch(sc->mlx_iftype) {
+ case MLX_IFTYPE_2:
+ /* These controllers don't report the firmware version in the ENQUIRY2 response */
+ if ((meo = mlx_enquire(sc, MLX_CMD_ENQUIRY_OLD, sizeof(struct mlx_enquiry_old), NULL)) == NULL) {
+ device_printf(sc->mlx_dev, "ENQUIRY_OLD failed\n");
+ return(ENXIO);
+ }
+ sc->mlx_enq2->me_firmware_id = ('0' << 24) | (0 << 16) | (meo->me_fwminor << 8) | meo->me_fwmajor;
+ free(meo, M_DEVBUF);
+
+ /* XXX require 2.42 or better (PCI) or 2.14 or better (EISA) */
+ if (meo->me_fwminor < 42) {
+ device_printf(sc->mlx_dev, " *** WARNING *** This firmware revision is not recommended\n");
+ device_printf(sc->mlx_dev, " *** WARNING *** Use revision 2.42 or later\n");
+ }
+ break;
case MLX_IFTYPE_3:
/* XXX certify 3.52? */
if (fwminor < 51) {
@@ -421,16 +468,19 @@ mlx_attach(struct mlx_softc *sc)
sc->mlx_check = -1;
/*
- * Register the control device on first attach.
+ * Create the control device.
*/
- if (cdev_registered++ == 0)
- cdevsw_add(&mlx_cdevsw);
+ sc->mlx_dev_t = make_dev(&mlx_cdevsw, device_get_unit(sc->mlx_dev), UID_ROOT, GID_OPERATOR,
+ S_IRUSR | S_IWUSR, "mlx%d", device_get_unit(sc->mlx_dev));
/*
* Start the timeout routine.
*/
sc->mlx_timeout = timeout(mlx_periodic, sc, hz);
+ /* print a little information about the controller */
+ mlx_describe_controller(sc);
+
return(0);
}
@@ -444,7 +494,7 @@ mlx_startup(struct mlx_softc *sc)
struct mlx_sysdrive *dr;
int i, error;
- debug("called");
+ debug_called(1);
/*
* Scan all the system drives and attach children for those that
@@ -504,7 +554,7 @@ mlx_detach(device_t dev)
struct mlxd_softc *mlxd;
int i, s, error;
- debug("called");
+ debug_called(1);
error = EBUSY;
s = splbio();
@@ -525,11 +575,6 @@ mlx_detach(device_t dev)
mlx_free(sc);
- /*
- * Deregister the control device on last detach.
- */
- if (--cdev_registered == 0)
- cdevsw_remove(&mlx_cdevsw);
error = 0;
out:
splx(s);
@@ -552,7 +597,7 @@ mlx_shutdown(device_t dev)
struct mlx_softc *sc = device_get_softc(dev);
int i, s, error;
- debug("called");
+ debug_called(1);
s = splbio();
error = 0;
@@ -591,7 +636,7 @@ mlx_suspend(device_t dev)
struct mlx_softc *sc = device_get_softc(dev);
int s;
- debug("called");
+ debug_called(1);
s = splbio();
sc->mlx_state |= MLX_STATE_SUSPEND;
@@ -614,7 +659,7 @@ mlx_resume(device_t dev)
{
struct mlx_softc *sc = device_get_softc(dev);
- debug("called");
+ debug_called(1);
sc->mlx_state &= ~MLX_STATE_SUSPEND;
sc->mlx_intaction(sc, MLX_INTACTION_ENABLE);
@@ -631,7 +676,7 @@ mlx_intr(void *arg)
{
struct mlx_softc *sc = (struct mlx_softc *)arg;
- debug("called");
+ debug_called(1);
/* collect finished commands, queue anything waiting */
mlx_done(sc);
@@ -646,7 +691,7 @@ mlx_submit_buf(struct mlx_softc *sc, struct buf *bp)
{
int s;
- debug("called");
+ debug_called(1);
s = splbio();
bufq_insert_tail(&sc->mlx_bufq, bp);
@@ -907,7 +952,7 @@ mlx_periodic(void *data)
{
struct mlx_softc *sc = (struct mlx_softc *)data;
- debug("called");
+ debug_called(1);
/*
* Run a bus pause?
@@ -946,7 +991,8 @@ mlx_periodic(void *data)
*
* XXX Note that this may not actually launch a command in situations of high load.
*/
- mlx_enquire(sc, MLX_CMD_ENQUIRY, sizeof(struct mlx_enquiry), mlx_periodic_enquiry);
+ mlx_enquire(sc, (sc->mlx_iftype == MLX_IFTYPE_2) ? MLX_CMD_ENQUIRY_OLD : MLX_CMD_ENQUIRY,
+ imax(sizeof(struct mlx_enquiry), sizeof(struct mlx_enquiry_old)), mlx_periodic_enquiry);
/*
* Check system drive status.
@@ -980,17 +1026,55 @@ mlx_periodic_enquiry(struct mlx_command *mc)
{
struct mlx_softc *sc = mc->mc_sc;
- debug("called");
+ debug_called(1);
/* Command completed OK? */
if (mc->mc_status != 0) {
- device_printf(sc->mlx_dev, "periodic enquiry failed\n");
+ device_printf(sc->mlx_dev, "periodic enquiry failed - %s\n", mlx_diagnose_command(mc));
goto out;
}
/* respond to command */
switch(mc->mc_mailbox[0]) {
/*
+ * This is currently a bit fruitless, as we don't know how to extract the eventlog
+ * pointer yet.
+ */
+ case MLX_CMD_ENQUIRY_OLD:
+ {
+ struct mlx_enquiry *me = (struct mlx_enquiry *)mc->mc_data;
+ struct mlx_enquiry_old *meo = (struct mlx_enquiry_old *)mc->mc_data;
+ int i;
+
+ /* convert data in-place to new format */
+ for (i = (sizeof(me->me_dead) / sizeof(me->me_dead[0])) - 1; i >= 0; i--) {
+ me->me_dead[i].dd_chan = meo->me_dead[i].dd_chan;
+ me->me_dead[i].dd_targ = meo->me_dead[i].dd_targ;
+ }
+ me->me_misc_flags = 0;
+ me->me_rebuild_count = meo->me_rebuild_count;
+ me->me_dead_count = meo->me_dead_count;
+ me->me_critical_sd_count = meo->me_critical_sd_count;
+ me->me_event_log_seq_num = 0;
+ me->me_offline_sd_count = meo->me_offline_sd_count;
+ me->me_max_commands = meo->me_max_commands;
+ me->me_rebuild_flag = meo->me_rebuild_flag;
+ me->me_fwmajor = meo->me_fwmajor;
+ me->me_fwminor = meo->me_fwminor;
+ me->me_status_flags = meo->me_status_flags;
+ me->me_flash_age = meo->me_flash_age;
+ for (i = (sizeof(me->me_drvsize) / sizeof(me->me_drvsize[0])) - 1; i >= 0; i--) {
+ if (i > ((sizeof(meo->me_drvsize) / sizeof(meo->me_drvsize[0])) - 1)) {
+ me->me_drvsize[i] = 0; /* drive beyond supported range */
+ } else {
+ me->me_drvsize[i] = meo->me_drvsize[i];
+ }
+ }
+ me->me_num_sys_drvs = meo->me_num_sys_drvs;
+ }
+ /* FALLTHROUGH */
+
+ /*
* Generic controller status update. We could do more with this than just
* checking the event log.
*/
@@ -1004,8 +1088,7 @@ mlx_periodic_enquiry(struct mlx_command *mc)
} else if (me->me_event_log_seq_num != sc->mlx_lastevent) {
/* record where current events are up to */
sc->mlx_currevent = me->me_event_log_seq_num;
- device_printf(sc->mlx_dev, "event log pointer was %d, now %d\n",
- sc->mlx_lastevent, sc->mlx_currevent);
+ debug(1, "event log pointer was %d, now %d\n", sc->mlx_lastevent, sc->mlx_currevent);
/* drain new eventlog entries */
mlx_periodic_eventlog_poll(sc);
@@ -1065,7 +1148,7 @@ mlx_periodic_eventlog_poll(struct mlx_softc *sc)
void *result = NULL;
int error;
- debug("called");
+ debug_called(1);
/* get ourselves a command buffer */
error = 1;
@@ -1129,7 +1212,7 @@ mlx_periodic_eventlog_respond(struct mlx_command *mc)
struct mlx_eventlog_entry *el = (struct mlx_eventlog_entry *)mc->mc_data;
char *reason;
- debug("called");
+ debug_called(1);
sc->mlx_lastevent++; /* next message... */
if (mc->mc_status == 0) {
@@ -1321,7 +1404,7 @@ mlx_enquire(struct mlx_softc *sc, int command, size_t bufsize, void (* complete)
void *result;
int error;
- debug("called");
+ debug_called(1);
/* get ourselves a command buffer */
error = 1;
@@ -1387,7 +1470,7 @@ mlx_flush(struct mlx_softc *sc)
struct mlx_command *mc;
int error;
- debug("called");
+ debug_called(1);
/* get ourselves a command buffer */
error = 1;
@@ -1429,7 +1512,7 @@ mlx_rebuild(struct mlx_softc *sc, int channel, int target)
struct mlx_command *mc;
int error;
- debug("called");
+ debug_called(1);
/* get ourselves a command buffer */
error = 0x10000;
@@ -1471,7 +1554,7 @@ mlx_wait_command(struct mlx_command *mc)
struct mlx_softc *sc = mc->mc_sc;
int error, count;
- debug("called");
+ debug_called(1);
mc->mc_complete = NULL;
mc->mc_private = mc; /* wake us when you're done */
@@ -1485,7 +1568,7 @@ mlx_wait_command(struct mlx_command *mc)
}
if (mc->mc_status != 0) {
- device_printf(sc->mlx_dev, "I/O error 0x%x\n", mc->mc_status);
+ device_printf(sc->mlx_dev, "command failed - %s\n", mlx_diagnose_command(mc));
return(EIO);
}
return(0);
@@ -1495,7 +1578,7 @@ mlx_wait_command(struct mlx_command *mc)
/********************************************************************************
* Start the command (mc) and busy-wait for it to complete.
*
- * Should only be used when interrupts are not available. Returns 0 on
+ * Should only be used when interrupts can't be relied upon. Returns 0 on
* success, nonzero on error.
* Successfully completed commands are dequeued.
*/
@@ -1505,7 +1588,7 @@ mlx_poll_command(struct mlx_command *mc)
struct mlx_softc *sc = mc->mc_sc;
int error, count, s;
- debug("called");
+ debug_called(1);
mc->mc_complete = NULL;
mc->mc_private = NULL; /* we will poll for it */
@@ -1516,7 +1599,8 @@ mlx_poll_command(struct mlx_command *mc)
do {
/* poll for completion */
mlx_done(mc->mc_sc);
- } while ((mc->mc_status == MLX_STATUS_BUSY) && (count < 10000));
+
+ } while ((mc->mc_status == MLX_STATUS_BUSY) && (count++ < 15000000));
if (mc->mc_status != MLX_STATUS_BUSY) {
s = splbio();
TAILQ_REMOVE(&sc->mlx_work, mc, mc_link);
@@ -1532,7 +1616,7 @@ mlx_poll_command(struct mlx_command *mc)
* controller. Leave a couple of slots free for emergencies.
*
* Must be called at splbio or in an equivalent fashion that prevents
- * reentry or activity on the bufq..
+ * reentry or activity on the bufq.
*/
static void
mlx_startio(struct mlx_softc *sc)
@@ -1576,10 +1660,10 @@ mlx_startio(struct mlx_softc *sc)
mc->mc_length = bp->b_bcount;
if (bp->b_flags & B_READ) {
mc->mc_flags |= MLX_CMD_DATAIN;
- cmd = MLX_CMD_READOLDSG;
+ cmd = MLX_CMD_READSG;
} else {
mc->mc_flags |= MLX_CMD_DATAOUT;
- cmd = MLX_CMD_WRITEOLDSG;
+ cmd = MLX_CMD_WRITESG;
}
/* map the command so the controller can work with it */
@@ -1598,14 +1682,22 @@ mlx_startio(struct mlx_softc *sc)
* Build the I/O command. Note that the SG list type bits are set to zero,
* denoting the format of SG list that we are using.
*/
- mlx_make_type5(mc, cmd,
- blkcount & 0xff, /* xfer length low byte */
- (driveno << 3) | ((blkcount >> 8) & 0x07), /* target and length high 3 bits */
- bp->b_pblkno, /* physical block number */
- mc->mc_sgphys, /* location of SG list */
- mc->mc_nsgent & 0x3f); /* size of SG list (top 2 bits clear) */
+ if (sc->mlx_iftype == MLX_IFTYPE_2) {
+ mlx_make_type1(mc, (cmd == MLX_CMD_WRITESG) ? MLX_CMD_WRITESG_OLD : MLX_CMD_READSG_OLD,
+ blkcount & 0xff, /* xfer length low byte */
+ bp->b_pblkno, /* physical block number */
+ driveno, /* target drive number */
+ mc->mc_sgphys, /* location of SG list */
+ mc->mc_nsgent & 0x3f); /* size of SG list (top 3 bits clear) */
+ } else {
+ mlx_make_type5(mc, cmd,
+ blkcount & 0xff, /* xfer length low byte */
+ (driveno << 3) | ((blkcount >> 8) & 0x07), /* target and length high 3 bits */
+ bp->b_pblkno, /* physical block number */
+ mc->mc_sgphys, /* location of SG list */
+ mc->mc_nsgent & 0x3f); /* size of SG list (top 3 bits clear) */
+ }
-
/* try to give command to controller */
if (mlx_start(mc) != 0) {
/* fail the command */
@@ -1655,51 +1747,79 @@ mlx_completeio(struct mlx_command *mc)
/********************************************************************************
* Take a command from user-space and try to run it.
+ *
+ * XXX Note that this can't perform very much in the way of error checking, and
+ * as such, applications _must_ be considered trustworthy.
+ * XXX Commands using S/G for data are not supported.
*/
static int
mlx_user_command(struct mlx_softc *sc, struct mlx_usercommand *mu)
{
struct mlx_command *mc;
+ struct mlx_dcdb *dcdb;
void *kbuf;
int error;
+ debug_called(0);
+
kbuf = NULL;
mc = NULL;
+ dcdb = NULL;
error = ENOMEM;
- /* get a kernel buffer for the transfer */
- if (mu->mu_datasize > 0) {
- if ((kbuf = malloc(mu->mu_datasize, M_DEVBUF, M_WAITOK)) == NULL)
- goto out;
- if ((mu->mu_bufptr < 0) || (mu->mu_bufptr > (sizeof(mu->mu_command) < sizeof(u_int32_t)))) {
- error = EINVAL;
- goto out;
- }
- }
- /* get ourselves a command buffer */
+
+ /* get ourselves a command and copy in from user space */
if ((mc = mlx_alloccmd(sc)) == NULL)
goto out;
-
- /* copy the command and data */
bcopy(mu->mu_command, mc->mc_mailbox, sizeof(mc->mc_mailbox));
- if ((mu->mu_datasize > 0) && ((error = copyin(mu->mu_buf, kbuf, mu->mu_datasize))))
- goto out;
+ debug(0, "got command buffer");
+
+ /* if we need a buffer for data transfer, allocate one and copy in its initial contents */
+ if (mu->mu_datasize > 0) {
+ if (((kbuf = malloc(mu->mu_datasize, M_DEVBUF, M_WAITOK)) == NULL) ||
+ (error = copyin(mu->mu_buf, kbuf, mu->mu_datasize)))
+ goto out;
+ debug(0, "got kernel buffer");
+ }
/* get a command slot */
if (mlx_getslot(mc))
goto out;
-
+ debug(0, "got a slot");
+
/* map the command so the controller can see it */
mc->mc_data = kbuf;
mc->mc_length = mu->mu_datasize;
mlx_mapcmd(mc);
+ debug(0, "mapped");
- /* if there's a data buffer, fix up the command */
+ /*
+ * If this is a passthrough SCSI command, the DCDB is packed at the
+ * beginning of the data area. Fix up the DCDB to point to the correct physical
+ * address and override any bufptr supplied by the caller since we know
+ * what it's meant to be.
+ */
+ if (mc->mc_mailbox[0] == MLX_CMD_DIRECT_CDB) {
+ dcdb = (struct mlx_dcdb *)kbuf;
+ dcdb->dcdb_physaddr = mc->mc_dataphys + sizeof(*dcdb);
+ mu->mu_bufptr = 8;
+ }
+
+ /*
+ * If there's a data buffer, fix up the command's buffer pointer.
+ */
if (mu->mu_datasize > 0) {
- mc->mc_mailbox[mu->mu_bufptr ] = mc->mc_length & 0xff;
- mc->mc_mailbox[mu->mu_bufptr + 1] = (mc->mc_length >> 8) & 0xff;
- mc->mc_mailbox[mu->mu_bufptr + 2] = (mc->mc_length >> 16) & 0xff;
- mc->mc_mailbox[mu->mu_bufptr + 3] = (mc->mc_length >> 24) & 0xff;
+
+ /* range check the pointer to physical buffer address */
+ if ((mu->mu_bufptr < 0) || (mu->mu_bufptr > (sizeof(mu->mu_command) - sizeof(u_int32_t)))) {
+ error = EINVAL;
+ goto out;
+ }
+ mc->mc_mailbox[mu->mu_bufptr ] = mc->mc_dataphys & 0xff;
+ mc->mc_mailbox[mu->mu_bufptr + 1] = (mc->mc_dataphys >> 8) & 0xff;
+ mc->mc_mailbox[mu->mu_bufptr + 2] = (mc->mc_dataphys >> 16) & 0xff;
+ mc->mc_mailbox[mu->mu_bufptr + 3] = (mc->mc_dataphys >> 24) & 0xff;
}
+ debug(0, "command fixup");
/* submit the command and wait */
if ((error = mlx_wait_command(mc)) != 0)
@@ -1736,7 +1856,7 @@ mlx_getslot(struct mlx_command *mc)
struct mlx_softc *sc = mc->mc_sc;
int s, slot;
- debug("called mc %p sc %p", mc, sc);
+ debug_called(1);
/* enforce slot-usage limit */
if (sc->mlx_busycmds >= ((mc->mc_flags & MLX_CMD_PRIORITY) ?
@@ -1750,7 +1870,7 @@ mlx_getslot(struct mlx_command *mc)
*/
s = splbio();
for (slot = 0; slot < sc->mlx_maxiop; slot++) {
- debug("try slot %d", slot);
+ debug(2, "try slot %d", slot);
if (sc->mlx_busycmd[slot] == NULL)
break;
}
@@ -1764,7 +1884,7 @@ mlx_getslot(struct mlx_command *mc)
if (slot >= sc->mlx_maxiop)
return(EBUSY);
- debug("got slot %d", slot);
+ debug(2, "got slot %d", slot);
mc->mc_slot = slot;
return(0);
}
@@ -1780,14 +1900,14 @@ mlx_setup_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error)
struct mlx_sgentry *sg;
int i;
- debug("called");
+ debug_called(1);
/* get base address of s/g table */
- sg = sc->mlx_sgtable + (mc->mc_slot * MLX_NSEG);
+ sg = sc->mlx_sgtable + (mc->mc_slot * sc->mlx_sg_nseg);
/* save s/g table information in command */
mc->mc_nsgent = nsegments;
- mc->mc_sgphys = sc->mlx_sgbusaddr + (mc->mc_slot * MLX_NSEG * sizeof(struct mlx_sgentry));
+ mc->mc_sgphys = sc->mlx_sgbusaddr + (mc->mc_slot * sc->mlx_sg_nseg * sizeof(struct mlx_sgentry));
mc->mc_dataphys = segs[0].ds_addr;
/* populate s/g table */
@@ -1802,7 +1922,7 @@ mlx_mapcmd(struct mlx_command *mc)
{
struct mlx_softc *sc = mc->mc_sc;
- debug("called");
+ debug_called(1);
/* if the command involves data at all */
if (mc->mc_data != NULL) {
@@ -1822,7 +1942,7 @@ mlx_unmapcmd(struct mlx_command *mc)
{
struct mlx_softc *sc = mc->mc_sc;
- debug("called");
+ debug_called(1);
/* if the command involved data at all */
if (mc->mc_data != NULL) {
@@ -1847,7 +1967,7 @@ mlx_start(struct mlx_command *mc)
struct mlx_softc *sc = mc->mc_sc;
int i, s, done;
- debug("called");
+ debug_called(1);
/* save the slot number as ident so we can handle this command when complete */
mc->mc_mailbox[0x1] = mc->mc_slot;
@@ -1899,7 +2019,7 @@ mlx_done(struct mlx_softc *sc)
u_int8_t slot;
u_int16_t status;
- debug("called");
+ debug_called(2);
result = 0;
@@ -1947,7 +2067,7 @@ mlx_complete(struct mlx_softc *sc)
struct mlx_command *mc, *nc;
int s, count;
- debug("called");
+ debug_called(2);
/* avoid reentrancy XXX might want to signal and request a restart */
if (mlx_lock_tas(sc, MLX_LOCK_COMPLETING))
@@ -2023,7 +2143,7 @@ mlx_alloccmd(struct mlx_softc *sc)
int error;
int s;
- debug("called");
+ debug_called(1);
s = splbio();
if ((mc = TAILQ_FIRST(&sc->mlx_freecmds)) != NULL)
@@ -2057,7 +2177,7 @@ mlx_releasecmd(struct mlx_command *mc)
{
int s;
- debug("called");
+ debug_called(1);
s = splbio();
TAILQ_INSERT_HEAD(&mc->mc_sc->mlx_freecmds, mc, mc_link);
@@ -2072,8 +2192,7 @@ mlx_freecmd(struct mlx_command *mc)
{
struct mlx_softc *sc = mc->mc_sc;
- debug("called");
-
+ debug_called(1);
bus_dmamap_destroy(sc->mlx_buffer_dmat, mc->mc_dmamap);
free(mc, M_DEVBUF);
}
@@ -2096,7 +2215,7 @@ mlx_v3_tryqueue(struct mlx_softc *sc, struct mlx_command *mc)
{
int i;
- debug("called");
+ debug_called(2);
/* ready for our command? */
if (!(MLX_V3_GET_IDBR(sc) & MLX_V3_IDB_FULL)) {
@@ -2121,7 +2240,7 @@ static int
mlx_v3_findcomplete(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status)
{
- debug("called");
+ debug_called(2);
/* status available? */
if (MLX_V3_GET_ODBR(sc) & MLX_V3_ODB_SAVAIL) {
@@ -2144,7 +2263,7 @@ mlx_v3_findcomplete(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status)
static void
mlx_v3_intaction(struct mlx_softc *sc, int action)
{
- debug("called");
+ debug_called(1);
switch(action) {
case MLX_INTACTION_DISABLE:
@@ -2158,6 +2277,45 @@ mlx_v3_intaction(struct mlx_softc *sc, int action)
}
}
+/********************************************************************************
+ * Poll for firmware error codes during controller initialisation.
+ * Returns 0 if initialisation is complete, 1 if still in progress but no
+ * error has been fetched, 2 if an error has been retrieved.
+ */
+static int
+mlx_v3_fw_handshake(struct mlx_softc *sc, int *error, int *param1, int *param2)
+{
+ u_int8_t fwerror;
+ static int initted = 0;
+
+ debug_called(2);
+
+ /* first time around, clear any hardware completion status */
+ if (!initted) {
+ MLX_V3_PUT_IDBR(sc, MLX_V3_IDB_SACK);
+ DELAY(1000);
+ initted = 1;
+ }
+
+ /* init in progress? */
+ if (!(MLX_V3_GET_IDBR(sc) & MLX_V3_IDB_INIT_BUSY))
+ return(0);
+
+ /* test error value */
+ fwerror = MLX_V3_GET_FWERROR(sc);
+ if (!(fwerror & MLX_V3_FWERROR_PEND))
+ return(1);
+
+ /* mask status pending bit, fetch status */
+ *error = fwerror & ~MLX_V3_FWERROR_PEND;
+ *param1 = MLX_V3_GET_FWERROR_PARAM1(sc);
+ *param2 = MLX_V3_GET_FWERROR_PARAM2(sc);
+
+ /* acknowledge */
+ MLX_V3_PUT_FWERROR(sc, 0);
+
+ return(2);
+}
/********************************************************************************
********************************************************************************
@@ -2176,7 +2334,7 @@ mlx_v4_tryqueue(struct mlx_softc *sc, struct mlx_command *mc)
{
int i;
- debug("called");
+ debug_called(2);
/* ready for our command? */
if (!(MLX_V4_GET_IDBR(sc) & MLX_V4_IDB_FULL)) {
@@ -2184,6 +2342,10 @@ mlx_v4_tryqueue(struct mlx_softc *sc, struct mlx_command *mc)
for (i = 0; i < 13; i++)
MLX_V4_PUT_MAILBOX(sc, i, mc->mc_mailbox[i]);
+ /* memory-mapped controller, so issue a write barrier to ensure the mailbox is filled */
+ bus_space_barrier(sc->mlx_btag, sc->mlx_bhandle, MLX_V4_MAILBOX, MLX_V4_MAILBOX_LENGTH,
+ BUS_SPACE_BARRIER_WRITE);
+
/* post command */
MLX_V4_PUT_IDBR(sc, MLX_V4_IDB_HWMBOX_CMD);
return(1);
@@ -2201,7 +2363,7 @@ static int
mlx_v4_findcomplete(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status)
{
- debug("called");
+ debug_called(2);
/* status available? */
if (MLX_V4_GET_ODBR(sc) & MLX_V4_ODB_HWSAVAIL) {
@@ -2224,7 +2386,7 @@ mlx_v4_findcomplete(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status)
static void
mlx_v4_intaction(struct mlx_softc *sc, int action)
{
- debug("called");
+ debug_called(1);
switch(action) {
case MLX_INTACTION_DISABLE:
@@ -2238,6 +2400,45 @@ mlx_v4_intaction(struct mlx_softc *sc, int action)
}
}
+/********************************************************************************
+ * Poll for firmware error codes during controller initialisation.
+ * Returns 0 if initialisation is complete, 1 if still in progress but no
+ * error has been fetched, 2 if an error has been retrieved.
+ */
+static int
+mlx_v4_fw_handshake(struct mlx_softc *sc, int *error, int *param1, int *param2)
+{
+ u_int8_t fwerror;
+ static int initted = 0;
+
+ debug_called(2);
+
+ /* first time around, clear any hardware completion status */
+ if (!initted) {
+ MLX_V4_PUT_IDBR(sc, MLX_V4_IDB_SACK);
+ DELAY(1000);
+ initted = 1;
+ }
+
+ /* init in progress? */
+ if (!(MLX_V4_GET_IDBR(sc) & MLX_V4_IDB_INIT_BUSY))
+ return(0);
+
+ /* test error value */
+ fwerror = MLX_V4_GET_FWERROR(sc);
+ if (!(fwerror & MLX_V4_FWERROR_PEND))
+ return(1);
+
+ /* mask status pending bit, fetch status */
+ *error = fwerror & ~MLX_V4_FWERROR_PEND;
+ *param1 = MLX_V4_GET_FWERROR_PARAM1(sc);
+ *param2 = MLX_V4_GET_FWERROR_PARAM2(sc);
+
+ /* acknowledge */
+ MLX_V4_PUT_FWERROR(sc, 0);
+
+ return(2);
+}
/********************************************************************************
********************************************************************************
@@ -2255,15 +2456,15 @@ static int
mlx_v5_tryqueue(struct mlx_softc *sc, struct mlx_command *mc)
{
int i;
-
- debug("called");
+
+ debug_called(2);
/* ready for our command? */
if (MLX_V5_GET_IDBR(sc) & MLX_V5_IDB_EMPTY) {
/* copy mailbox data to window */
for (i = 0; i < 13; i++)
MLX_V5_PUT_MAILBOX(sc, i, mc->mc_mailbox[i]);
-
+
/* post command */
MLX_V5_PUT_IDBR(sc, MLX_V5_IDB_HWMBOX_CMD);
return(1);
@@ -2281,7 +2482,7 @@ static int
mlx_v5_findcomplete(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status)
{
- debug("called");
+ debug_called(2);
/* status available? */
if (MLX_V5_GET_ODBR(sc) & MLX_V5_ODB_HWSAVAIL) {
@@ -2304,20 +2505,59 @@ mlx_v5_findcomplete(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status)
static void
mlx_v5_intaction(struct mlx_softc *sc, int action)
{
- debug("called");
+ debug_called(1);
switch(action) {
case MLX_INTACTION_DISABLE:
- MLX_V5_PUT_IER(sc, MLX_V5_IER_DISINT);
+ MLX_V5_PUT_IER(sc, 0xff & MLX_V5_IER_DISINT);
sc->mlx_state &= ~MLX_STATE_INTEN;
break;
case MLX_INTACTION_ENABLE:
- MLX_V5_PUT_IER(sc, 0);
+ MLX_V5_PUT_IER(sc, 0xff & ~MLX_V5_IER_DISINT);
sc->mlx_state |= MLX_STATE_INTEN;
break;
}
}
+/********************************************************************************
+ * Poll for firmware error codes during controller initialisation.
+ * Returns 0 if initialisation is complete, 1 if still in progress but no
+ * error has been fetched, 2 if an error has been retrieved.
+ */
+static int
+mlx_v5_fw_handshake(struct mlx_softc *sc, int *error, int *param1, int *param2)
+{
+ u_int8_t fwerror;
+ static int initted = 0;
+
+ debug_called(2);
+
+ /* first time around, clear any hardware completion status */
+ if (!initted) {
+ MLX_V5_PUT_IDBR(sc, MLX_V5_IDB_SACK);
+ DELAY(1000);
+ initted = 1;
+ }
+
+ /* init in progress? */
+ if (MLX_V5_GET_IDBR(sc) & MLX_V5_IDB_INIT_DONE)
+ return(0);
+
+ /* test for error value */
+ fwerror = MLX_V5_GET_FWERROR(sc);
+ if (!(fwerror & MLX_V5_FWERROR_PEND))
+ return(1);
+
+ /* mask status pending bit, fetch status */
+ *error = fwerror & ~MLX_V5_FWERROR_PEND;
+ *param1 = MLX_V5_GET_FWERROR_PARAM1(sc);
+ *param2 = MLX_V5_GET_FWERROR_PARAM2(sc);
+
+ /* acknowledge */
+ MLX_V5_PUT_FWERROR(sc, 0xff);
+
+ return(2);
+}
/********************************************************************************
********************************************************************************
@@ -2343,6 +2583,13 @@ static char *mlx_status_messages[] = {
"invalid or non-redundant drive", /* 11 */
"channel is busy", /* 12 */
"channel is not stopped", /* 13 */
+ "rebuild successfully terminated", /* 14 */
+ "unsupported command", /* 15 */
+ "check condition received", /* 16 */
+ "device is busy", /* 17 */
+ "selection or command timeout", /* 18 */
+ "command terminated abnormally", /* 19 */
+ ""
};
static struct
@@ -2351,18 +2598,25 @@ static struct
u_int16_t status;
int msg;
} mlx_messages[] = {
- {MLX_CMD_READOLDSG, 0x0001, 1},
- {MLX_CMD_READOLDSG, 0x0002, 1},
- {MLX_CMD_READOLDSG, 0x0105, 3},
- {MLX_CMD_READOLDSG, 0x010c, 4},
- {MLX_CMD_WRITEOLDSG, 0x0001, 1},
- {MLX_CMD_WRITEOLDSG, 0x0002, 1},
- {MLX_CMD_WRITEOLDSG, 0x0105, 3},
+ {MLX_CMD_READSG, 0x0001, 1},
+ {MLX_CMD_READSG, 0x0002, 1},
+ {MLX_CMD_READSG, 0x0105, 3},
+ {MLX_CMD_READSG, 0x010c, 4},
+ {MLX_CMD_WRITESG, 0x0001, 1},
+ {MLX_CMD_WRITESG, 0x0002, 1},
+ {MLX_CMD_WRITESG, 0x0105, 3},
+ {MLX_CMD_READSG_OLD, 0x0001, 1},
+ {MLX_CMD_READSG_OLD, 0x0002, 1},
+ {MLX_CMD_READSG_OLD, 0x0105, 3},
+ {MLX_CMD_WRITESG_OLD, 0x0001, 1},
+ {MLX_CMD_WRITESG_OLD, 0x0002, 1},
+ {MLX_CMD_WRITESG_OLD, 0x0105, 3},
{MLX_CMD_LOGOP, 0x0105, 5},
{MLX_CMD_REBUILDASYNC, 0x0002, 6},
{MLX_CMD_REBUILDASYNC, 0x0004, 7},
{MLX_CMD_REBUILDASYNC, 0x0105, 8},
{MLX_CMD_REBUILDASYNC, 0x0106, 9},
+ {MLX_CMD_REBUILDASYNC, 0x0107, 14},
{MLX_CMD_CHECKASYNC, 0x0002, 10},
{MLX_CMD_CHECKASYNC, 0x0105, 11},
{MLX_CMD_CHECKASYNC, 0x0106, 9},
@@ -2370,6 +2624,13 @@ static struct
{MLX_CMD_STOPCHANNEL, 0x0105, 8},
{MLX_CMD_STARTCHANNEL, 0x0005, 13},
{MLX_CMD_STARTCHANNEL, 0x0105, 8},
+ {MLX_CMD_DIRECT_CDB, 0x0002, 16},
+ {MLX_CMD_DIRECT_CDB, 0x0008, 17},
+ {MLX_CMD_DIRECT_CDB, 0x000e, 18},
+ {MLX_CMD_DIRECT_CDB, 0x000f, 19},
+ {MLX_CMD_DIRECT_CDB, 0x0105, 8},
+
+ {0, 0x0104, 14},
{-1, 0, 0}
};
@@ -2381,7 +2642,7 @@ mlx_diagnose_command(struct mlx_command *mc)
/* look up message in table */
for (i = 0; mlx_messages[i].command != -1; i++)
- if ((mc->mc_mailbox[0] == mlx_messages[i].command) &&
+ if (((mc->mc_mailbox[0] == mlx_messages[i].command) || (mlx_messages[i].command == 0)) &&
(mc->mc_status == mlx_messages[i].status))
return(mlx_status_messages[mlx_messages[i].msg]);
@@ -2390,7 +2651,7 @@ mlx_diagnose_command(struct mlx_command *mc)
}
/*******************************************************************************
- * Return a string describing the controller (hwid)
+ * Print a string describing the controller (sc)
*/
static struct
{
@@ -2427,7 +2688,7 @@ mlx_describe_controller(struct mlx_softc *sc)
sprintf(buf, " model 0x%x", sc->mlx_enq2->me_hardware_id & 0xff);
model = buf;
}
- device_printf(sc->mlx_dev, "DAC%s, %d channel%s, firmware %d.%02d-%c-%d, %dMB RAM\n",
+ device_printf(sc->mlx_dev, "DAC%s, %d channel%s, firmware %d.%02d-%c-%02d, %dMB RAM\n",
model,
sc->mlx_enq2->me_actual_channels,
sc->mlx_enq2->me_actual_channels > 1 ? "s" : "",
@@ -2476,6 +2737,59 @@ mlx_describe_controller(struct mlx_softc *sc)
}
}
+/*******************************************************************************
+ * Emit a string describing the firmware handshake status code, and return a flag
+ * indicating whether the code represents a fatal error.
+ *
+ * Error code interpretations are from the Linux driver, and don't directly match
+ * the messages printed by Mylex's BIOS. This may change if documentation on the
+ * codes is forthcoming.
+ */
+static int
+mlx_fw_message(struct mlx_softc *sc, int error, int param1, int param2)
+{
+ switch(error) {
+ case 0x00:
+ device_printf(sc->mlx_dev, "physical drive %d:%d not responding\n", param2, param1);
+ break;
+ case 0x08:
+ /* we could be neater about this and give some indication when we receive more of them */
+ if (!(sc->mlx_flags & MLX_SPINUP_REPORTED)) {
+ device_printf(sc->mlx_dev, "spinning up drives...\n");
+ sc->mlx_flags |= MLX_SPINUP_REPORTED;
+ }
+ break;
+ case 0x30:
+ device_printf(sc->mlx_dev, "configuration checksum error\n");
+ break;
+ case 0x60:
+ device_printf(sc->mlx_dev, "mirror race recovery failed\n");
+ break;
+ case 0x70:
+ device_printf(sc->mlx_dev, "mirror race recovery in progress\n");
+ break;
+ case 0x90:
+ device_printf(sc->mlx_dev, "physical drive %d:%d COD mismatch\n", param2, param1);
+ break;
+ case 0xa0:
+ device_printf(sc->mlx_dev, "logical drive installation aborted\n");
+ break;
+ case 0xb0:
+ device_printf(sc->mlx_dev, "mirror race on a critical system drive\n");
+ break;
+ case 0xd0:
+ device_printf(sc->mlx_dev, "new controller configuration found\n");
+ break;
+ case 0xf0:
+ device_printf(sc->mlx_dev, "FATAL MEMORY PARITY ERROR\n");
+ return(1);
+ default:
+ device_printf(sc->mlx_dev, "unknown firmware initialisation error %02x:%02x:%02x\n", error, param1, param2);
+ break;
+ }
+ return(0);
+}
+
/********************************************************************************
********************************************************************************
Utility Functions
diff --git a/sys/dev/mlx/mlx_disk.c b/sys/dev/mlx/mlx_disk.c
index acd3d79..1dcf93b 100644
--- a/sys/dev/mlx/mlx_disk.c
+++ b/sys/dev/mlx/mlx_disk.c
@@ -50,12 +50,6 @@
#include <dev/mlx/mlxvar.h>
#include <dev/mlx/mlxreg.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);
@@ -111,7 +105,7 @@ mlxd_open(dev_t dev, int flags, int fmt, struct proc *p)
struct mlxd_softc *sc = (struct mlxd_softc *)dev->si_drv1;
struct disklabel *label;
- debug("called");
+ debug_called(1);
if (sc == NULL)
return (ENXIO);
@@ -139,7 +133,7 @@ mlxd_close(dev_t dev, int flags, int fmt, struct proc *p)
{
struct mlxd_softc *sc = (struct mlxd_softc *)dev->si_drv1;
- debug("called");
+ debug_called(1);
if (sc == NULL)
return (ENXIO);
@@ -153,13 +147,13 @@ mlxd_ioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p)
struct mlxd_softc *sc = (struct mlxd_softc *)dev->si_drv1;
int error;
- debug("called");
+ debug_called(1);
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);
+ debug(0, "mlx_submit_ioctl returned %d\n", error);
return(error);
}
return (ENOTTY);
@@ -176,7 +170,7 @@ mlxd_strategy(struct buf *bp)
{
struct mlxd_softc *sc = (struct mlxd_softc *)bp->b_dev->si_drv1;
- debug("called");
+ debug_called(1);
/* bogus disk? */
if (sc == NULL) {
@@ -216,7 +210,7 @@ mlxd_intr(void *data)
struct buf *bp = (struct buf *)data;
struct mlxd_softc *sc = (struct mlxd_softc *)bp->b_dev->si_drv1;
- debug("called");
+ debug_called(1);
if (bp->b_flags & B_ERROR)
bp->b_error = EIO;
@@ -231,7 +225,7 @@ static int
mlxd_probe(device_t dev)
{
- debug("called");
+ debug_called(1);
device_set_desc(dev, "Mylex System Drive");
return (0);
@@ -245,7 +239,7 @@ mlxd_attach(device_t dev)
char *state;
dev_t dsk;
- debug("called");
+ debug_called(1);
parent = device_get_parent(dev);
sc->mlxd_controller = (struct mlx_softc *)device_get_softc(parent);
@@ -291,7 +285,7 @@ mlxd_detach(device_t dev)
{
struct mlxd_softc *sc = (struct mlxd_softc *)device_get_softc(dev);
- debug("called");
+ debug_called(1);
devstat_remove_entry(&sc->mlxd_stats);
diff --git a/sys/dev/mlx/mlx_pci.c b/sys/dev/mlx/mlx_pci.c
index 6448a52..004c9aa 100644
--- a/sys/dev/mlx/mlx_pci.c
+++ b/sys/dev/mlx/mlx_pci.c
@@ -50,12 +50,6 @@
#include <dev/mlx/mlxvar.h>
#include <dev/mlx/mlxreg.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);
@@ -90,7 +84,7 @@ struct mlx_ident
int iftype;
char *desc;
} mlx_identifiers[] = {
-/* {0x1069, 0x0001, 0x0000, 0x0000, MLX_IFTYPE_2, "Mylex version 2 RAID interface"}, */
+ {0x1069, 0x0001, 0x0000, 0x0000, MLX_IFTYPE_2, "Mylex version 2 RAID interface"},
{0x1069, 0x0002, 0x0000, 0x0000, MLX_IFTYPE_3, "Mylex version 3 RAID interface"},
{0x1069, 0x0010, 0x0000, 0x0000, MLX_IFTYPE_4, "Mylex version 4 RAID interface"},
{0x1011, 0x1065, 0x1069, 0x0020, MLX_IFTYPE_5, "Mylex version 5 RAID interface"},
@@ -102,7 +96,7 @@ mlx_pci_probe(device_t dev)
{
struct mlx_ident *m;
- debug("called");
+ debug_called(1);
for (m = mlx_identifiers; m->vendor != 0; m++) {
if ((m->vendor == pci_get_vendor(dev)) &&
@@ -124,16 +118,19 @@ mlx_pci_attach(device_t dev)
int i, rid, error;
u_int32_t command;
- debug("called");
+ debug_called(1);
/*
* Make sure we are going to be able to talk to this board.
*/
- command = pci_read_config(dev, PCIR_COMMAND, 1);
+ command = pci_read_config(dev, PCIR_COMMAND, 2);
if ((command & PCIM_CMD_MEMEN) == 0) {
device_printf(dev, "memory window not available\n");
return(ENXIO);
}
+ /* force the busmaster enable bit on */
+ command |= PCIM_CMD_BUSMASTEREN;
+ pci_write_config(dev, PCIR_COMMAND, command, 2);
/*
* Initialise softc.
@@ -161,8 +158,17 @@ mlx_pci_attach(device_t dev)
* 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;
+ /* type 2/3 adapters have an I/O region we don't use at base 0 */
+ switch(sc->mlx_iftype) {
+ case MLX_IFTYPE_2:
+ case MLX_IFTYPE_3:
+ rid = MLX_CFG_BASE1;
+ break;
+ case MLX_IFTYPE_4:
+ case MLX_IFTYPE_5:
+ rid = MLX_CFG_BASE0;
+ break;
+ }
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");
@@ -180,7 +186,7 @@ mlx_pci_attach(device_t dev)
BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
BUS_SPACE_MAXADDR, /* highaddr */
NULL, NULL, /* filter, filterarg */
- MAXBSIZE, MLX_NSEG, /* maxsize, nsegments */
+ MAXBSIZE, MLX_NSEG_NEW, /* maxsize, nsegments */
BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
BUS_DMA_ALLOCNOW, /* flags */
&sc->mlx_parent_dmat);
diff --git a/sys/dev/mlx/mlxio.h b/sys/dev/mlx/mlxio.h
index eabeb50..984b223 100644
--- a/sys/dev/mlx/mlxio.h
+++ b/sys/dev/mlx/mlxio.h
@@ -79,6 +79,10 @@ struct mlx_usercommand
/* command */
u_int16_t mu_status; /* command status returned */
u_int8_t mu_command[16]; /* command mailbox contents */
+
+ /* wrapper */
+ int mu_error; /* result of submission to driver */
+
};
#define MLX_NEXT_CHILD _IOWR('M', 0, int)
@@ -86,3 +90,4 @@ struct mlx_usercommand
#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)
+
diff --git a/sys/dev/mlx/mlxreg.h b/sys/dev/mlx/mlxreg.h
index d004a12c..c5382bf 100644
--- a/sys/dev/mlx/mlxreg.h
+++ b/sys/dev/mlx/mlxreg.h
@@ -26,19 +26,19 @@
* $FreeBSD$
*/
-#define MLX_CFG_BASE0 0x10 /* first region */
-#define MLX_CFG_BASE1 0x14 /* second region (type 3 only) */
-
#define MLX_BLKSIZE 512 /* fixed feature */
/*
* Selected command codes.
*/
+#define MLX_CMD_ENQUIRY_OLD 0x05
#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_READSG 0xb6
+#define MLX_CMD_WRITESG 0xb7
+#define MLX_CMD_READSG_OLD 0x82
+#define MLX_CMD_WRITESG_OLD 0x83
#define MLX_CMD_FLUSH 0x0a
#define MLX_CMD_LOGOP 0x72
#define MLX_CMD_REBUILDASYNC 0x16
@@ -46,6 +46,13 @@
#define MLX_CMD_REBUILDSTAT 0x0c
#define MLX_CMD_STOPCHANNEL 0x13
#define MLX_CMD_STARTCHANNEL 0x12
+#define MLX_CMD_READ_CONFIG 0x4e
+#define MLX_CMD_DIRECT_CDB 0x04
+
+#ifdef _KERNEL
+
+#define MLX_CFG_BASE0 0x10 /* first region */
+#define MLX_CFG_BASE1 0x14 /* second region (type 3 only) */
/*
* Status values.
@@ -65,6 +72,9 @@
#define MLX_V3_IDBR 0x40
#define MLX_V3_ODBR 0x41
#define MLX_V3_IER 0x43
+#define MLX_V3_FWERROR 0x3f
+#define MLX_V3_FWERROR_PARAM1 0x00
+#define MLX_V3_FWERROR_PARAM2 0x01
#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)
@@ -74,21 +84,33 @@
#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_GET_FWERROR(sc) bus_space_read_1 (sc->mlx_btag, sc->mlx_bhandle, MLX_V3_FWERROR)
+#define MLX_V3_PUT_FWERROR(sc, val) bus_space_write_1(sc->mlx_btag, sc->mlx_bhandle, MLX_V3_FWERROR, val)
+#define MLX_V3_GET_FWERROR_PARAM1(sc) bus_space_read_1 (sc->mlx_btag, sc->mlx_bhandle, MLX_V3_FWERROR_PARAM1)
+#define MLX_V3_GET_FWERROR_PARAM2(sc) bus_space_read_1 (sc->mlx_btag, sc->mlx_bhandle, MLX_V3_FWERROR_PARAM2)
#define MLX_V3_IDB_FULL (1<<0) /* mailbox is full */
+#define MLX_V3_IDB_INIT_BUSY (1<<1) /* initialisation in progress */
+
#define MLX_V3_IDB_SACK (1<<1) /* acknowledge status read */
#define MLX_V3_ODB_SAVAIL (1<<0) /* status is available */
+#define MLX_V3_FWERROR_PEND (1<<2) /* firmware error pending */
+
/*
* Accessor defines for the V4 interface.
*/
#define MLX_V4_MAILBOX 0x1000
-#define MLX_V4_STATUS_IDENT 0x1018
+#define MLX_V4_MAILBOX_LENGTH 16
+#define MLX_V4_STATUS_IDENT 0x1018
#define MLX_V4_STATUS 0x101a
#define MLX_V4_IDBR 0x0020
#define MLX_V4_ODBR 0x002c
#define MLX_V4_IER 0x0034
+#define MLX_V4_FWERROR 0x103f
+#define MLX_V4_FWERROR_PARAM1 0x1000
+#define MLX_V4_FWERROR_PARAM2 0x1001
/* use longword access? */
#define MLX_V4_PUT_MAILBOX(sc, idx, val) bus_space_write_1(sc->mlx_btag, sc->mlx_bhandle, MLX_V4_MAILBOX + idx, val)
@@ -99,8 +121,13 @@
#define MLX_V4_GET_ODBR(sc) bus_space_read_4 (sc->mlx_btag, sc->mlx_bhandle, MLX_V4_ODBR)
#define MLX_V4_PUT_ODBR(sc, val) bus_space_write_4(sc->mlx_btag, sc->mlx_bhandle, MLX_V4_ODBR, val)
#define MLX_V4_PUT_IER(sc, val) bus_space_write_4(sc->mlx_btag, sc->mlx_bhandle, MLX_V4_IER, val)
+#define MLX_V4_GET_FWERROR(sc) bus_space_read_1 (sc->mlx_btag, sc->mlx_bhandle, MLX_V4_FWERROR)
+#define MLX_V4_PUT_FWERROR(sc, val) bus_space_write_1(sc->mlx_btag, sc->mlx_bhandle, MLX_V4_FWERROR, val)
+#define MLX_V4_GET_FWERROR_PARAM1(sc) bus_space_read_1 (sc->mlx_btag, sc->mlx_bhandle, MLX_V4_FWERROR_PARAM1)
+#define MLX_V4_GET_FWERROR_PARAM2(sc) bus_space_read_1 (sc->mlx_btag, sc->mlx_bhandle, MLX_V4_FWERROR_PARAM2)
#define MLX_V4_IDB_FULL (1<<0) /* mailbox is full */
+#define MLX_V4_IDB_INIT_BUSY (1<<1) /* initialisation in progress */
#define MLX_V4_IDB_HWMBOX_CMD (1<<0) /* posted hardware mailbox command */
#define MLX_V4_IDB_SACK (1<<1) /* acknowledge status read */
@@ -115,15 +142,21 @@
#define MLX_V4_IER_MASK 0xfb /* message unit interrupt mask */
#define MLX_V4_IER_DISINT (1<<2) /* interrupt disable bit */
+#define MLX_V4_FWERROR_PEND (1<<2) /* firmware error pending */
+
/*
* Accessor defines for the V5 interface
*/
#define MLX_V5_MAILBOX 0x50
+#define MLX_V5_MAILBOX_LENGTH 16
#define MLX_V5_STATUS_IDENT 0x5d
#define MLX_V5_STATUS 0x5e
#define MLX_V5_IDBR 0x60
#define MLX_V5_ODBR 0x61
#define MLX_V5_IER 0x34
+#define MLX_V5_FWERROR 0x63
+#define MLX_V5_FWERROR_PARAM1 0x50
+#define MLX_V5_FWERROR_PARAM2 0x51
#define MLX_V5_PUT_MAILBOX(sc, idx, val) bus_space_write_1(sc->mlx_btag, sc->mlx_bhandle, MLX_V5_MAILBOX + idx, val)
#define MLX_V5_GET_STATUS_IDENT(sc) bus_space_read_1 (sc->mlx_btag, sc->mlx_bhandle, MLX_V5_STATUS_IDENT)
@@ -133,11 +166,17 @@
#define MLX_V5_GET_ODBR(sc) bus_space_read_1 (sc->mlx_btag, sc->mlx_bhandle, MLX_V5_ODBR)
#define MLX_V5_PUT_ODBR(sc, val) bus_space_write_1(sc->mlx_btag, sc->mlx_bhandle, MLX_V5_ODBR, val)
#define MLX_V5_PUT_IER(sc, val) bus_space_write_1(sc->mlx_btag, sc->mlx_bhandle, MLX_V5_IER, val)
+#define MLX_V5_GET_FWERROR(sc) bus_space_read_1 (sc->mlx_btag, sc->mlx_bhandle, MLX_V5_FWERROR)
+#define MLX_V5_PUT_FWERROR(sc, val) bus_space_write_1(sc->mlx_btag, sc->mlx_bhandle, MLX_V5_FWERROR, val)
+#define MLX_V5_GET_FWERROR_PARAM1(sc) bus_space_read_1 (sc->mlx_btag, sc->mlx_bhandle, MLX_V5_FWERROR_PARAM1)
+#define MLX_V5_GET_FWERROR_PARAM2(sc) bus_space_read_1 (sc->mlx_btag, sc->mlx_bhandle, MLX_V5_FWERROR_PARAM2)
#define MLX_V5_IDB_EMPTY (1<<0) /* mailbox is empty */
+#define MLX_V5_IDB_INIT_DONE (1<<1) /* initialisation has completed */
#define MLX_V5_IDB_HWMBOX_CMD (1<<0) /* posted hardware mailbox command */
#define MLX_V5_IDB_SACK (1<<1) /* acknowledge status read */
+#define MLX_V5_IDB_RESET (1<<3) /* reset request */
#define MLX_V5_IDB_MEMMBOX_CMD (1<<4) /* posted memory mailbox command */
#define MLX_V5_ODB_HWSAVAIL (1<<0) /* status is available for hardware mailbox */
@@ -148,6 +187,9 @@
#define MLX_V5_IER_DISINT (1<<2) /* interrupt disable bit */
+#define MLX_V5_FWERROR_PEND (1<<2) /* firmware error pending */
+
+#endif /* _KERNEL */
/*
* Scatter-gather list format, type 1, kind 00.
@@ -161,6 +203,34 @@ struct mlx_sgentry
/*
* Command result buffers, as placed in system memory by the controller.
*/
+
+struct mlx_enquiry_old /* MLX_CMD_ENQUIRY_OLD */
+{
+ u_int8_t me_num_sys_drvs;
+ u_int8_t res1[3];
+ u_int32_t me_drvsize[8];
+ u_int16_t me_flash_age;
+ u_int8_t me_status_flags;
+ u_int8_t me_free_state_change_count;
+ 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_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;
+ struct
+ {
+ u_int8_t dd_targ;
+ u_int8_t dd_chan;
+ } __attribute__ ((packed)) me_dead[20];
+} __attribute__ ((packed));
+
struct mlx_enquiry /* MLX_CMD_ENQUIRY */
{
u_int8_t me_num_sys_drvs;
@@ -285,6 +355,135 @@ struct mlx_rebuild_stat /* MLX_CMD_REBUILDSTAT */
u_int32_t rb_remaining;
} __attribute__ ((packed));
+struct mlx_config2
+{
+ u_int16_t cf_flags1;
+#define MLX_CF2_ACTV_NEG (1<<1)
+#define MLX_CF2_NORSTRTRY (1<<7)
+#define MLX_CF2_STRGWRK (1<<8)
+#define MLX_CF2_HPSUPP (1<<9)
+#define MLX_CF2_NODISCN (1<<10)
+#define MLX_CF2_ARM (1<<13)
+#define MLX_CF2_OFM (1<<15)
+#define MLX_CF2_AEMI (MLX_CF2_ARM | MLX_CF2_OFM)
+ u_int8_t cf_oemid;
+ u_int8_t cf_oem_model;
+ u_int8_t cf_physical_sector;
+ u_int8_t cf_logical_sector;
+ u_int8_t cf_blockfactor;
+ u_int8_t cf_flags2;
+#define MLX_CF2_READAH (1<<0)
+#define MLX_CF2_BIOSDLY (1<<1)
+#define MLX_CF2_REASS1S (1<<4)
+#define MLX_CF2_FUAENABL (1<<6)
+#define MLX_CF2_R5ALLS (1<<7)
+ u_int8_t cf_rcrate;
+ u_int8_t cf_res1;
+ u_int8_t cf_blocks_per_cache_line;
+ u_int8_t cf_blocks_per_stripe;
+ u_int8_t cf_scsi_param_0;
+ u_int8_t cf_scsi_param_1;
+ u_int8_t cf_scsi_param_2;
+ u_int8_t cf_scsi_param_3;
+ u_int8_t cf_scsi_param_4;
+ u_int8_t cf_scsi_param_5;
+ u_int8_t cf_scsi_initiator_id;
+ u_int8_t cf_res2;
+ u_int8_t cf_startup_mode;
+ u_int8_t cf_simultaneous_spinup_devices;
+ u_int8_t cf_delay_between_spinups;
+ u_int8_t cf_res3;
+ u_int16_t cf_checksum;
+} __attribute__ ((packed));
+
+struct mlx_sys_drv_span
+{
+ u_int32_t sp_start_lba;
+ u_int32_t sp_nblks;
+ u_int8_t sp_arm[8];
+} __attribute__ ((packed));
+
+struct mlx_sys_drv
+{
+ u_int8_t sd_status;
+ u_int8_t sd_ext_status;
+ u_int8_t sd_mod1;
+ u_int8_t sd_mod2;
+ u_int8_t sd_raidlevel;
+#define MLX_SYS_DRV_WRITEBACK (1<<7)
+#define MLX_SYS_DRV_RAID0 0
+#define MLX_SYS_DRV_RAID1 1
+#define MLX_SYS_DRV_RAID3 3
+#define MLX_SYS_DRV_RAID5 5
+#define MLX_SYS_DRV_RAID6 6
+#define MLX_SYS_DRV_JBOD 7
+ u_int8_t sd_valid_arms;
+ u_int8_t sd_valid_spans;
+ u_int8_t sd_init_state;
+#define MLX_SYS_DRV_INITTED 0x81;
+ struct mlx_sys_drv_span sd_span[4];
+} __attribute__ ((packed));
+
+struct mlx_phys_drv
+{
+ u_int8_t pd_flags1;
+#define MLX_PHYS_DRV_PRESENT (1<<0)
+ u_int8_t pd_flags2;
+#define MLX_PHYS_DRV_OTHER 0x00
+#define MLX_PHYS_DRV_DISK 0x01
+#define MLX_PHYS_DRV_SEQUENTIAL 0x02
+#define MLX_PHYS_DRV_CDROM 0x03
+#define MLX_PHYS_DRV_FAST20 (1<<3)
+#define MLX_PHYS_DRV_SYNC (1<<4)
+#define MLX_PHYS_DRV_FAST (1<<5)
+#define MLX_PHYS_DRV_WIDE (1<<6)
+#define MLX_PHYS_DRV_TAG (1<<7)
+ u_int8_t pd_status;
+#define MLX_PHYS_DRV_DEAD 0x00
+#define MLX_PHYS_DRV_WRONLY 0x02
+#define MLX_PHYS_DRV_ONLINE 0x03
+#define MLX_PHYS_DRV_STANDBY 0x10
+ u_int8_t pd_res1;
+ u_int8_t pd_period;
+ u_int8_t pd_offset;
+ u_int32_t pd_config_size;
+} __attribute__ ((packed));
+
+struct mlx_core_cfg
+{
+ u_int8_t cc_num_sys_drives;
+ u_int8_t cc_res1[3];
+ struct mlx_sys_drv cc_sys_drives[32];
+ struct mlx_phys_drv cc_phys_drives[5 * 16];
+} __attribute__ ((packed));
+
+struct mlx_dcdb
+{
+ u_int8_t dcdb_target:4;
+ u_int8_t dcdb_channel:4;
+ u_int8_t dcdb_flags;
+#define MLX_DCDB_NO_DATA 0x00
+#define MLX_DCDB_DATA_IN 0x01
+#define MLX_DCDB_DATA_OUT 0x02
+#define MLX_DCDB_EARLY_STATUS (1<<2)
+#define MLX_DCDB_TIMEOUT_10S 0x10
+#define MLX_DCDB_TIMEOUT_60S 0x20
+#define MLX_DCDB_TIMEOUT_20M 0x30
+#define MLX_DCDB_TIMEOUT_24H 0x40
+#define MLX_DCDB_NO_AUTO_SENSE (1<<6)
+#define MLX_DCDB_DISCONNECT (1<<7)
+ u_int16_t dcdb_datasize;
+ u_int32_t dcdb_physaddr;
+ u_int8_t dcdb_cdb_length:4;
+ u_int8_t dcdb_datasize_high:4;
+ u_int8_t dcdb_sense_length;
+ u_int8_t dcdb_cdb[12];
+ u_int8_t dcdb_sense[64];
+ u_int8_t dcdb_status;
+ u_int8_t res1;
+} __attribute__ ((packed));
+
+#ifdef _KERNEL
/*
* Inlines to build various command structures
*/
@@ -406,3 +605,5 @@ mlx_make_type5(struct mlx_command *mc,
mc->mc_mailbox[0xb] = (f4 >> 24) & 0xff;
mc->mc_mailbox[0xc] = f5;
}
+
+#endif /* _KERNEL */
diff --git a/sys/dev/mlx/mlxvar.h b/sys/dev/mlx/mlxvar.h
index 3465358..7847ca2 100644
--- a/sys/dev/mlx/mlxvar.h
+++ b/sys/dev/mlx/mlxvar.h
@@ -27,14 +27,30 @@
*/
/*
- * 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
+ * Debugging levels:
+ * 0 - quiet, only emit warnings
+ * 1 - noisy, emit major function points and things done
+ * 2 - extremely noisy, emit trace items in loops, etc.
+ */
+#ifdef MLX_DEBUG
+#define debug(level, fmt, args...) do { if (level <= MLX_DEBUG) printf("%s: " fmt "\n", __FUNCTION__ , ##args); } while(0)
+#define debug_called(level) do { if (level <= MLX_DEBUG) printf(__FUNCTION__ ": called\n"); } while(0)
+#else
+#define debug(level, fmt, args...)
+#define debug_called(level)
+#endif
+
+
+/*
+ * We could actually use all 17/33 segments, but using only 16/32 means that
+ * each scatter/gather map is 128/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_NSEG_OLD 16 /* max scatter/gather segments we use 3.x and earlier */
+#define MLX_NSEG_NEW 32 /* max scatter/gather segments we use 4.x and later */
#define MLX_NSLOTS 256 /* max number of command slots */
-#define MLX_MAXDRIVES 32
+#define MLX_MAXDRIVES 32 /* max number of system drives */
/*
* Structure describing a System Drive as attached to the controller.
@@ -90,6 +106,7 @@ struct mlx_softc
{
/* bus connections */
device_t mlx_dev;
+ dev_t mlx_dev_t;
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 */
@@ -103,6 +120,7 @@ struct mlx_softc
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 */
+ int mlx_sg_nseg; /* max number of s/g entries */
/* controller limits and features */
struct mlx_enquiry2 *mlx_enq2;
@@ -138,15 +156,19 @@ struct mlx_softc
struct mlx_pause mlx_pause; /* pending pause operation details */
int mlx_locks; /* reentrancy avoidance */
+ int mlx_flags;
+#define MLX_SPINUP_REPORTED (1<<0) /* "spinning up drives" message displayed */
/* interface-specific accessor functions */
int mlx_iftype; /* interface protocol */
+#define MLX_IFTYPE_2 2
#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);
+ int (* mlx_fw_handshake)(struct mlx_softc *sc, int *error, int *param1, int *param2);
#define MLX_INTACTION_DISABLE 0
#define MLX_INTACTION_ENABLE 1
};
OpenPOWER on IntegriCloud