Updates resulting from new documentation from Mylex and some cleaning:

- Don't keep private copies of some of the data fields from the
   ENQUIRY and ENQUIRY2 commands.  Instead, standardise on the ENQUIRY2
   command for initial adapter information, and keep a copy of the entire
   structure.  Refer to it where appropriate.

 - Move all of the controller description functionality into a new
   function.  Print lots more controller data if bootverbose is set.
   Add knowledge of the DAC960 PR, PT, PTL0 and PRL controllers, rename
   the 960PTL -> PTL0 and 1100P -> 1100PVX.

 - Correctly terminate an error message.

The controller interface procedures have been reviewed against the
Mylex-supplied documentation; no changes appear necessary at this
time.
This commit is contained in:
Mike Smith 1999-12-22 01:21:28 +00:00
parent 3b073b53b7
commit 9eee27f16d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=54979
4 changed files with 95 additions and 75 deletions

View File

@ -142,7 +142,7 @@ static void mlx_complete(struct mlx_softc *sc);
* Debugging.
*/
static char *mlx_diagnose_command(struct mlx_command *mc);
static char *mlx_name_controller(u_int32_t hwid);
static void mlx_describe_controller(struct mlx_softc *sc);
/*
@ -201,6 +201,10 @@ mlx_free(struct mlx_softc *sc)
if (sc->mlx_mem != NULL)
bus_release_resource(sc->mlx_dev, SYS_RES_MEMORY,
(sc->mlx_iftype == MLX_IFTYPE_3) ? MLX_CFG_BASE1 : MLX_CFG_BASE0, sc->mlx_mem);
/* free controller enquiry data */
if (sc->mlx_enq2 != NULL)
free(sc->mlx_enq2, M_DEVBUF);
}
/********************************************************************************
@ -273,9 +277,7 @@ mlx_sglist_map(struct mlx_softc *sc)
int
mlx_attach(struct mlx_softc *sc)
{
struct mlx_enquiry *me;
struct mlx_enquiry2 *me2;
int rid, error;
int rid, error, fwminor;
debug("called");
@ -350,69 +352,48 @@ mlx_attach(struct mlx_softc *sc)
/*
* Create an initial set of s/g mappings.
*/
sc->mlx_maxiop = 2;
sc->mlx_maxiop = 8;
error = mlx_sglist_map(sc);
if (error != 0) {
device_printf(sc->mlx_dev, "couldn't make initial s/g list mapping\n");
return(error);
}
/*
* Probe the controller for more information.
*/
/* send an ENQUIRY to the controller */
if ((me = mlx_enquire(sc, MLX_CMD_ENQUIRY, sizeof(*me), NULL)) == NULL) {
device_printf(sc->mlx_dev, "ENQUIRY failed\n");
return(ENXIO);
}
/* pull information out of the ENQUIRY result */
sc->mlx_fwminor = me->me_fwminor;
sc->mlx_fwmajor = me->me_fwmajor;
sc->mlx_maxiop = me->me_max_commands;
sc->mlx_lastevent = sc->mlx_currevent = me->me_event_log_seq_num;
free(me, M_DEVBUF);
/* send an ENQUIRY2 to the controller */
if ((me2 = mlx_enquire(sc, MLX_CMD_ENQUIRY2, sizeof(*me2), NULL)) == NULL) {
if ((sc->mlx_enq2 = mlx_enquire(sc, MLX_CMD_ENQUIRY2, sizeof(struct mlx_enquiry2), NULL)) == NULL) {
device_printf(sc->mlx_dev, "ENQUIRY2 failed\n");
return(ENXIO);
}
/* pull information out of the ENQUIRY2 result */
sc->mlx_nchan = me2->me_configured_channels;
sc->mlx_maxiosize = me2->me_maxblk;
sc->mlx_maxtarg = me2->me_max_targets;
sc->mlx_maxtags = me2->me_max_tags;
sc->mlx_scsicap = me2->me_scsi_cap;
sc->mlx_hwid = me2->me_hardware_id;
/*
* We don't (yet) know where the event log is up to.
*/
sc->mlx_lastevent = -1;
/* print a little information about the controller and ourselves */
device_printf(sc->mlx_dev, "Mylex %s, firmware %d.%02d, %dMB RAM\n",
mlx_name_controller(sc->mlx_hwid), sc->mlx_fwmajor, sc->mlx_fwminor,
me2->me_mem_size / (1024 * 1024));
free(me2, M_DEVBUF);
/* 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_3:
/* XXX certify 3.52? */
if (sc->mlx_fwminor < 51) {
if (fwminor < 51) {
device_printf(sc->mlx_dev, " *** WARNING *** This firmware revision is not recommended\n");
device_printf(sc->mlx_dev, " *** WARNING *** Use revision 3.51 or later\n");
}
break;
case MLX_IFTYPE_4:
/* XXX certify firmware versions? */
if (sc->mlx_fwminor < 6) {
if (fwminor < 6) {
device_printf(sc->mlx_dev, " *** WARNING *** This firmware revision is not recommended\n");
device_printf(sc->mlx_dev, " *** WARNING *** Use revision 4.06 or later\n");
}
break;
case MLX_IFTYPE_5:
if (sc->mlx_fwminor < 7) {
if (fwminor < 7) {
device_printf(sc->mlx_dev, " *** WARNING *** This firmware revision is not recommended\n");
device_printf(sc->mlx_dev, " *** WARNING *** Use revision 5.07 or later\n");
}
@ -426,6 +407,7 @@ mlx_attach(struct mlx_softc *sc)
* Create the final set of s/g mappings now that we know how many commands
* the controller actually supports.
*/
sc->mlx_maxiop = sc->mlx_enq2->me_max_commands;
error = mlx_sglist_map(sc);
if (error != 0) {
device_printf(sc->mlx_dev, "couldn't make initial s/g list mapping\n");
@ -470,7 +452,7 @@ mlx_startup(struct mlx_softc *sc)
*/
mes = mlx_enquire(sc, MLX_CMD_ENQSYSDRIVE, sizeof(*mes) * MLX_MAXDRIVES, NULL);
if (mes == NULL) {
device_printf(sc->mlx_dev, "error fetching drive status");
device_printf(sc->mlx_dev, "error fetching drive status\n");
return;
}
@ -798,7 +780,7 @@ mlx_ioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p)
sc->mlx_pause.mp_which = 0;
} else {
/* fix for legal channels */
mp->mp_which &= ((1 << sc->mlx_nchan) -1);
mp->mp_which &= ((1 << sc->mlx_enq2->me_actual_channels) -1);
/* check time values */
if ((mp->mp_when < 0) || (mp->mp_when > 3600))
return(EINVAL);
@ -1016,14 +998,16 @@ mlx_periodic_enquiry(struct mlx_command *mc)
{
struct mlx_enquiry *me = (struct mlx_enquiry *)mc->mc_data;
/* New stuff in the event log? */
if (me->me_event_log_seq_num != sc->mlx_lastevent) {
if (sc->mlx_lastevent == -1) {
/* initialise our view of the event log */
sc->mlx_currevent = sc->mlx_lastevent = me->me_event_log_seq_num;
} 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);
/* start poll of event log */
/* drain new eventlog entries */
mlx_periodic_eventlog_poll(sc);
}
break;
@ -1269,7 +1253,7 @@ mlx_pause_action(struct mlx_softc *sc)
}
/* build commands for every channel requested */
for (i = 0; i < sc->mlx_nchan; i++) {
for (i = 0; i < sc->mlx_enq2->me_actual_channels; i++) {
if ((1 << i) & sc->mlx_pause.mp_which) {
/* get ourselves a command buffer */
@ -1750,13 +1734,13 @@ static int
mlx_getslot(struct mlx_command *mc)
{
struct mlx_softc *sc = mc->mc_sc;
int s, slot, limit;
int s, slot;
debug("called mc %p sc %p", mc, sc);
/* enforce slot-usage limit */
limit = (mc->mc_flags & MLX_CMD_PRIORITY) ? sc->mlx_maxiop : sc->mlx_maxiop - 4;
if (sc->mlx_busycmds > limit)
if (sc->mlx_busycmds >= ((mc->mc_flags & MLX_CMD_PRIORITY) ?
sc->mlx_maxiop : sc->mlx_maxiop - 4))
return(EBUSY);
/*
@ -1977,10 +1961,6 @@ mlx_complete(struct mlx_softc *sc)
while (mc != NULL) {
nc = TAILQ_NEXT(mc, mc_link);
/* XXX this is slightly bogus */
if (count++ > (sc->mlx_maxiop * 2))
panic("mlx_work list corrupt!");
/* Command has been completed in some fashion */
if (mc->mc_status != MLX_STATUS_BUSY) {
@ -2421,31 +2401,79 @@ static struct
{0x02, "960PL"},
{0x10, "960PG"},
{0x11, "960PJ"},
{0x16, "960PTL"},
{0x20, "1164P"},
{0x12, "960PR"},
{0x13, "960PT"},
{0x14, "960PTL0"},
{0x15, "960PRL"},
{0x16, "960PTL1"},
{0x20, "1164PVX"},
{-1, NULL}
};
static char *
mlx_name_controller(u_int32_t hwid)
static void
mlx_describe_controller(struct mlx_softc *sc)
{
static char buf[80];
char *model;
int nchn, i;
int i;
for (i = 0, model = NULL; mlx_controller_names[i].name != NULL; i++) {
if ((hwid & 0xff) == mlx_controller_names[i].hwid) {
if ((sc->mlx_enq2->me_hardware_id & 0xff) == mlx_controller_names[i].hwid) {
model = mlx_controller_names[i].name;
break;
}
}
if (model == NULL) {
sprintf(buf, " model 0x%x", hwid & 0xff);
sprintf(buf, " model 0x%x", sc->mlx_enq2->me_hardware_id & 0xff);
model = buf;
}
nchn = (hwid >> 8) & 0xff;
sprintf(buf, "DAC%s, %d channel%s", model, nchn, nchn > 1 ? "s" : "");
return(buf);
device_printf(sc->mlx_dev, "DAC%s, %d channel%s, firmware %d.%02d-%c-%d, %dMB RAM\n",
model,
sc->mlx_enq2->me_actual_channels,
sc->mlx_enq2->me_actual_channels > 1 ? "s" : "",
sc->mlx_enq2->me_firmware_id & 0xff,
(sc->mlx_enq2->me_firmware_id >> 8) & 0xff,
(sc->mlx_enq2->me_firmware_id >> 16),
(sc->mlx_enq2->me_firmware_id >> 24) & 0xff,
sc->mlx_enq2->me_mem_size / (1024 * 1024));
if (bootverbose) {
device_printf(sc->mlx_dev, " Hardware ID 0x%08x\n", sc->mlx_enq2->me_hardware_id);
device_printf(sc->mlx_dev, " Firmware ID 0x%08x\n", sc->mlx_enq2->me_firmware_id);
device_printf(sc->mlx_dev, " Configured/Actual channels %d/%d\n", sc->mlx_enq2->me_configured_channels,
sc->mlx_enq2->me_actual_channels);
device_printf(sc->mlx_dev, " Max Targets %d\n", sc->mlx_enq2->me_max_targets);
device_printf(sc->mlx_dev, " Max Tags %d\n", sc->mlx_enq2->me_max_tags);
device_printf(sc->mlx_dev, " Max System Drives %d\n", sc->mlx_enq2->me_max_sys_drives);
device_printf(sc->mlx_dev, " Max Arms %d\n", sc->mlx_enq2->me_max_arms);
device_printf(sc->mlx_dev, " Max Spans %d\n", sc->mlx_enq2->me_max_spans);
device_printf(sc->mlx_dev, " DRAM/cache/flash/NVRAM size %d/%d/%d/%d\n", sc->mlx_enq2->me_mem_size,
sc->mlx_enq2->me_cache_size, sc->mlx_enq2->me_flash_size, sc->mlx_enq2->me_nvram_size);
device_printf(sc->mlx_dev, " DRAM type %d\n", sc->mlx_enq2->me_mem_type);
device_printf(sc->mlx_dev, " Clock Speed %dns\n", sc->mlx_enq2->me_clock_speed);
device_printf(sc->mlx_dev, " Hardware Speed %dns\n", sc->mlx_enq2->me_hardware_speed);
device_printf(sc->mlx_dev, " Max Commands %d\n", sc->mlx_enq2->me_max_commands);
device_printf(sc->mlx_dev, " Max SG Entries %d\n", sc->mlx_enq2->me_max_sg);
device_printf(sc->mlx_dev, " Max DP %d\n", sc->mlx_enq2->me_max_dp);
device_printf(sc->mlx_dev, " Max IOD %d\n", sc->mlx_enq2->me_max_iod);
device_printf(sc->mlx_dev, " Max Comb %d\n", sc->mlx_enq2->me_max_comb);
device_printf(sc->mlx_dev, " Latency %ds\n", sc->mlx_enq2->me_latency);
device_printf(sc->mlx_dev, " SCSI Timeout %ds\n", sc->mlx_enq2->me_scsi_timeout);
device_printf(sc->mlx_dev, " Min Free Lines %d\n", sc->mlx_enq2->me_min_freelines);
device_printf(sc->mlx_dev, " Rate Constant %d\n", sc->mlx_enq2->me_rate_const);
device_printf(sc->mlx_dev, " MAXBLK %d\n", sc->mlx_enq2->me_maxblk);
device_printf(sc->mlx_dev, " Blocking Factor %d sectors\n", sc->mlx_enq2->me_blocking_factor);
device_printf(sc->mlx_dev, " Cache Line Size %d blocks\n", sc->mlx_enq2->me_cacheline);
device_printf(sc->mlx_dev, " SCSI Capability %s%dMHz, %d bit\n",
sc->mlx_enq2->me_scsi_cap & (1<<4) ? "differential " : "",
(1 << ((sc->mlx_enq2->me_scsi_cap >> 2) & 3)) * 10,
8 << (sc->mlx_enq2->me_scsi_cap & 0x3));
device_printf(sc->mlx_dev, " Firmware Build Number %d\n", sc->mlx_enq2->me_firmware_build);
device_printf(sc->mlx_dev, " Fault Management Type %d\n", sc->mlx_enq2->me_fault_mgmt_type);
device_printf(sc->mlx_dev, " Features %b\n", sc->mlx_enq2->me_firmware_features,
"\20\4Background Init\3Read Ahead\2MORE\1Cluster\n");
}
}
/********************************************************************************

View File

@ -281,7 +281,7 @@ mlxd_attach(device_t dev)
disks_registered++;
/* set maximum I/O size */
dsk->si_iosize_max = sc->mlxd_controller->mlx_maxiosize * MLX_BLKSIZE;
dsk->si_iosize_max = sc->mlxd_controller->mlx_enq2->me_maxblk * MLX_BLKSIZE;
return (0);
}

View File

@ -214,7 +214,7 @@ struct mlx_enquiry2 /* MLX_CMD_ENQUIRY2 */
u_int16_t me_clock_speed;
u_int16_t me_mem_speed;
u_int16_t me_hardware_speed;
u_int8_t res4[10];
u_int8_t res4[12];
u_int16_t me_max_commands;
u_int16_t me_max_sg;
u_int16_t me_max_dp;
@ -235,7 +235,7 @@ struct mlx_enquiry2 /* MLX_CMD_ENQUIRY2 */
u_int16_t me_cacheline;
u_int8_t me_scsi_cap;
u_int8_t res9[5];
u_int16_t me_fimware_build;
u_int16_t me_firmware_build;
u_int8_t me_fault_mgmt_type;
u_int8_t res10;
u_int32_t me_firmware_features;

View File

@ -105,13 +105,8 @@ struct mlx_softc
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 */
struct mlx_enquiry2 *mlx_enq2;
int mlx_maxiop; /* hard maximum number of commands */
int mlx_feature; /* controller features/quirks */
#define MLX_FEAT_PAUSEWORKS (1<<0) /* channel pause works as expected */
@ -125,8 +120,6 @@ struct mlx_softc
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
@ -137,9 +130,8 @@ struct mlx_softc
#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_lastevent; /* sequence number of the last event we recorded */
int mlx_currevent; /* sequence number last time we looked */
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 */