Exemple #1
0
static int
debug_config(int ac, char **av)
{
	struct mfi_config_data *config;
	int error, fd;

	if (ac != 1) {
		warnx("debug: extra arguments");
		return (EINVAL);
	}

	fd = mfi_open(mfi_unit);
	if (fd < 0) {
		error = errno;
		warn("mfi_open");
		return (error);
	}

	/* Get the config from the controller. */
	if (mfi_config_read(fd, &config) < 0) {
		error = errno;
		warn("Failed to get config");
		close(fd);
		return (error);
	}

	/* Dump out the configuration. */
	dump_config(fd, config);
	free(config);
	close(fd);

	return (0);
}
Exemple #2
0
static int
foreign_clear(__unused int ac, __unused char **av)
{
	int ch, error, fd;

	fd = mfi_open(mfi_unit, O_RDWR);
	if (fd < 0) {
		error = errno;
		warn("mfi_open");
		return (error);
	}

	printf(
	    "Are you sure you wish to clear ALL foreign configurations"
	    " on mfi%u? [y/N] ", mfi_unit);

	ch = getchar();
	if (ch != 'y' && ch != 'Y') {
		printf("\nAborting\n");
		close(fd);
		return (0);
	}

	if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_CLEAR, NULL, 0, NULL,
	    0, NULL) < 0) {
		error = errno;
		warn("Failed to clear foreign configuration");
		close(fd);
		return (error);
	}

	printf("mfi%d: Foreign configuration cleared\n", mfi_unit);
	close(fd);
	return (0);
}
Exemple #3
0
static int
foreign_scan(__unused int ac, __unused char **av)
{
	struct mfi_foreign_scan_info info;
	int error, fd;

	fd = mfi_open(mfi_unit, O_RDONLY);
	if (fd < 0) {
		error = errno;
		warn("mfi_open");
		return (error);
	}

	if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_SCAN, &info,
	    sizeof(info), NULL, 0, NULL) < 0) {
		error = errno;
		warn("Failed to scan foreign configuration");
		close(fd);
		return (error);
	}

	printf("mfi%d: Found %d foreign configurations\n", mfi_unit,
	       info.count);
	close(fd);
	return (0);
}
Exemple #4
0
static int
clear_config(int ac, char **av)
{
	struct mfi_ld_list list;
	int ch, error, fd;
	u_int i;

	fd = mfi_open(mfi_unit);
	if (fd < 0) {
		error = errno;
		warn("mfi_open");
		return (error);
	}

	if (!mfi_reconfig_supported()) {
		warnx("The current mfi(4) driver does not support "
		    "configuration changes.");
		close(fd);
		return (EOPNOTSUPP);
	}

	if (mfi_ld_get_list(fd, &list, NULL) < 0) {
		error = errno;
		warn("Failed to get volume list");
		close(fd);
		return (error);
	}

	for (i = 0; i < list.ld_count; i++) {
		if (mfi_volume_busy(fd, list.ld_list[i].ld.v.target_id)) {
			warnx("Volume %s is busy and cannot be deleted",
			    mfi_volume_name(fd, list.ld_list[i].ld.v.target_id));
			close(fd);
			return (EBUSY);
		}
	}

	printf(
	    "Are you sure you wish to clear the configuration on mfi%u? [y/N] ",
	    mfi_unit);
	ch = getchar();
	if (ch != 'y' && ch != 'Y') {
		printf("\nAborting\n");
		close(fd);
		return (0);
	}

	if (mfi_dcmd_command(fd, MFI_DCMD_CFG_CLEAR, NULL, 0, NULL, 0, NULL) < 0) {
		error = errno;
		warn("Failed to clear configuration");
		close(fd);
		return (error);
	}

	printf("mfi%d: Configuration cleared\n", mfi_unit);
	close(fd);

	return (0);
}
Exemple #5
0
int
display_format(int ac, char **av, int diagnostic, mfi_dcmd_t display_cmd)
{
	struct mfi_foreign_scan_info info;
	uint8_t i;
	int error, fd;

	if (ac > 2) {
		warnx("foreign display: extra arguments");
                return (EINVAL);
	}

	fd = mfi_open(mfi_unit, O_RDONLY);
	if (fd < 0) {
		error = errno;
		warn("mfi_open");
		return (error);
	}

	if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_SCAN, &info,
	    sizeof(info), NULL, 0, NULL) < 0) {
		error = errno;
		warn("Failed to scan foreign configuration");
		close(fd);
		return (error);
	}

	if (info.count == 0) {
		warnx("foreign display: no foreign configs found");
		close(fd);
		return (EINVAL);
	}

	if (ac == 1) {
		for (i = 0; i < info.count; i++) {
			error = foreign_show_cfg(fd,
				display_cmd, i, diagnostic);
			if(error != 0) {
				close(fd);
				return (error);
			}
			if (i < info.count - 1)
				printf("\n");
		}
	} else if (ac == 2) {
		error = foreign_show_cfg(fd,
			display_cmd, atoi(av[1]), diagnostic);
		if (error != 0) {
			close(fd);
			return (error);
		}
	}
	
	close(fd);
	return (0);
}
Exemple #6
0
static int
remove_spare(int ac, char **av)
{
	struct mfi_pd_info info;
	int error, fd;
	uint16_t device_id;
	uint8_t mbox[4];

	if (ac != 2) {
		warnx("remove spare: drive required");
		return (EINVAL);
	}

	fd = mfi_open(mfi_unit);
	if (fd < 0) {
		error = errno;
		warn("mfi_open");
		return (error);
	}

	error = mfi_lookup_drive(fd, av[1], &device_id);
	if (error) {
		close(fd);
		return (error);
	}

	/* Get the info for this drive. */
	if (mfi_pd_get_info(fd, device_id, &info, NULL) < 0) {
		error = errno;
		warn("Failed to fetch info for drive %u", device_id);
		close(fd);
		return (error);
	}

	if (info.fw_state != MFI_PD_STATE_HOT_SPARE) {
		warnx("Drive %u is not a hot spare", device_id);
		close(fd);
		return (EINVAL);
	}

	mbox_store_pdref(mbox, &info.ref);
	if (mfi_dcmd_command(fd, MFI_DCMD_CFG_REMOVE_SPARE, NULL, 0, mbox,
	    sizeof(mbox), NULL) < 0) {
		error = errno;
		warn("Failed to delete spare");
		close(fd);
		return (error);
	}

	close(fd);

	return (0);
}
Exemple #7
0
/*
 * aquite the controller properties data structure modify the 
 * rebuild rate if requested and then retun
 */
static int
mfi_ctrl_rebuild_rate(int ac, char **av)
{
	int error, fd;
	struct mfi_ctrl_props ctrl_props;

	if (ac > 2) {
		warn("mfi_ctrl_set_rebuild_rate");
		return(-1);
	}
		
	fd = mfi_open(mfi_unit, O_RDWR);
	if (fd < 0) {
		error = errno;
		warn("mfi_open");
		return (error);
	}

	error = mfi_ctrl_get_properties(fd, &ctrl_props);
	if ( error < 0) {
		error = errno;
		warn("Failed to get controller properties");
		close(fd);
		return (error);
	}
	/*
	 * User requested a change to the rebuild rate
	 */
	if (ac > 1) {
		ctrl_props.rebuild_rate = atoi(av[ac - 1]);
		error = mfi_ctrl_set_properties(fd, &ctrl_props);
		if ( error < 0) {
			error = errno;
			warn("Failed to set controller properties");
			close(fd);
			return (error);
		}

		error = mfi_ctrl_get_properties(fd, &ctrl_props);
		if ( error < 0) {
			error = errno;
			warn("Failed to get controller properties");
			close(fd);
			return (error);
		}
	}
	printf ("controller rebuild rate: %%%u \n",
		ctrl_props.rebuild_rate);
	return (0);
}
Exemple #8
0
static int
mfi_ctrl_alarm_enable(int ac, char **av)
{
	int error, fd;
	struct mfi_ctrl_props ctrl_props;

	if (ac > 2) {
		warn("mfi_ctrl_alarm_enable");
		return(-1);
	}
		
	fd = mfi_open(mfi_unit, O_RDWR);
	if (fd < 0) {
		error = errno;
		warn("mfi_open");
		return (error);
	}

	error = mfi_ctrl_get_properties(fd, &ctrl_props);
	if ( error < 0) {
		error = errno;
		warn("Failed to get controller properties");
		close(fd);
		return (error);
	}
	printf ("controller alarm was : %s\n",
		(ctrl_props.alarm_enable ? "enabled" : "disabled"));

	if (ac > 1) {
		ctrl_props.alarm_enable = atoi(av[ac - 1]);
		error = mfi_ctrl_set_properties(fd, &ctrl_props);
		if ( error < 0) {
			error = errno;
			warn("Failed to set controller properties");
			close(fd);
			return (error);
		}

		error = mfi_ctrl_get_properties(fd, &ctrl_props);
		if ( error < 0) {
			error = errno;
			warn("Failed to get controller properties");
			close(fd);
			return (error);
		}
	}
	printf ("controller alarm was : %s\n",
		(ctrl_props.alarm_enable ? "enabled" : "disabled"));
	return (0);
}
Exemple #9
0
static int
dump(int ac, char **av)
{
	struct mfi_config_data *config;
	char buf[64];
	size_t len;
	int error, fd;

	if (ac != 1) {
		warnx("dump: extra arguments");
		return (EINVAL);
	}

	fd = mfi_open(mfi_unit);
	if (fd < 0) {
		error = errno;
		warn("mfi_open");
		return (error);
	}

	/* Get the stashed copy of the last dcmd from the driver. */
	snprintf(buf, sizeof(buf), "dev.mfi.%d.debug_command", mfi_unit);
	if (sysctlbyname(buf, NULL, &len, NULL, 0) < 0) {
		error = errno;
		warn("Failed to read debug command");
		if (error == ENOENT)
			error = EOPNOTSUPP;
		close(fd);
		return (error);
	}

	config = malloc(len);
	if (config == NULL) {
		warnx("malloc failed");
		close(fd);
		return (ENOMEM);
	}
	if (sysctlbyname(buf, config, &len, NULL, 0) < 0) {
		error = errno;
		warn("Failed to read debug command");
		free(config);
		close(fd);
		return (error);
	}
	dump_config(fd, config);
	free(config);
	close(fd);

	return (0);
}
Exemple #10
0
static int
stop_patrol(int ac, char **av)
{
	int error, fd;

	fd = mfi_open(mfi_unit);
	if (fd < 0) {
		error = errno;
		warn("mfi_open");
		return (error);
	}

	if (mfi_dcmd_command(fd, MFI_DCMD_PR_STOP, NULL, 0, NULL, 0, NULL) <
	    0) {
		error = errno;
		warn("Failed to stop patrol read");
		return (error);
	}

	close(fd);

	return (0);
}
Exemple #11
0
static int
show_logstate(int ac, __unused char **av)
{
	struct mfi_evt_log_state info;
	int error, fd;

	if (ac != 1) {
		warnx("show logstate: extra arguments");
		return (EINVAL);
	}

	fd = mfi_open(mfi_unit);
	if (fd < 0) {
		error = errno;
		warn("mfi_open");
		return (error);
	}

	if (mfi_event_get_info(fd, &info, NULL) < 0) {
		error = errno;
		warn("Failed to get event log info");
		close(fd);
		return (error);
	}

	printf("mfi%d Event Log Sequence Numbers:\n", mfi_unit);
	printf("  Newest Seq #: %u\n", info.newest_seq_num);
	printf("  Oldest Seq #: %u\n", info.oldest_seq_num);
	printf("   Clear Seq #: %u\n", info.clear_seq_num);
	printf("Shutdown Seq #: %u\n", info.shutdown_seq_num);
	printf("    Boot Seq #: %u\n", info.boot_seq_num);

	close(fd);

	return (0);
}
Exemple #12
0
static int
foreign_import(int ac, char **av)
{
	struct mfi_foreign_scan_info info;
	int ch, error, fd;
	uint8_t cfgidx;
	uint8_t mbox[4];

	if (ac > 2) {
		warnx("foreign preview: extra arguments");
                return (EINVAL);
	}

	fd = mfi_open(mfi_unit, O_RDWR);
	if (fd < 0) {
		error = errno;
		warn("mfi_open");
		return (error);
	}

	if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_SCAN, &info,
	    sizeof(info), NULL, 0, NULL) < 0) {
		error = errno;
		warn("Failed to scan foreign configuration");
		close(fd);
		return (error);
	}

	if (info.count == 0) {
		warnx("foreign import: no foreign configs found");
		close(fd);
		return (EINVAL);
	}

	if (ac == 1) {
		cfgidx = 0xff;
		printf("Are you sure you wish to import ALL foreign "
		       "configurations on mfi%u? [y/N] ", mfi_unit);
	} else {
		/*
		 * While this is docmmented for MegaCli this failed with
		 * exit code 0x03 on the test controller which was a Supermicro
		 * SMC2108 with firmware 12.12.0-0095 which is a LSI 2108 based
		 * controller.
		 */
		cfgidx = atoi(av[1]);
		if (cfgidx >= info.count) {
			warnx("Invalid foreign config %d specified max is %d",
			      cfgidx, info.count - 1);
			close(fd);
			return (EINVAL);
		}
		printf("Are you sure you wish to import the foreign "
		       "configuration %d on mfi%u? [y/N] ", cfgidx, mfi_unit);
	}

	ch = getchar();
	if (ch != 'y' && ch != 'Y') {
		printf("\nAborting\n");
		close(fd);
		return (0);
	}

	bzero(mbox, sizeof(mbox));
	mbox[0] = cfgidx;
	if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_IMPORT, NULL, 0, mbox,
	    sizeof(mbox), NULL) < 0) {
		error = errno;
		warn("Failed to import foreign configuration");
		close(fd);
		return (error);
	}

	if (ac == 1)
		printf("mfi%d: All foreign configurations imported\n",
		       mfi_unit);
	else
		printf("mfi%d: Foreign configuration %d imported\n", mfi_unit,
		       cfgidx);
	close(fd);
	return (0);
}
		if (ld->properties.ld.v.target_id == target_id)
			return (ld);
		p += config->log_drv_size;
	}

	return (NULL);
}

static int
clear_config(int ac __unused, char **av __unused)
{
	struct mfi_ld_list list;
	int ch, error, fd;
	u_int i;

	fd = mfi_open(mfi_unit, O_RDWR);
	if (fd < 0) {
		error = errno;
		warn("mfi_open");
		return (error);
	}

	if (!mfi_reconfig_supported()) {
		warnx("The current mfi(4) driver does not support "
		    "configuration changes.");
		close(fd);
		return (EOPNOTSUPP);
	}

	if (mfi_ld_get_list(fd, &list, NULL) < 0) {
		error = errno;
Exemple #14
0
/*
 * Print the name of a drive either by drive number as %2u or by enclosure:slot
 * as Exx:Sxx (or both).  Use default unless command line options override it
 * and the command allows this (which we usually do unless we already print
 * both).  We prefer pinfo if given, otherwise try to look it up by device_id.
 */
const char *
mfi_drive_name(struct mfi_pd_info *pinfo, uint16_t device_id, uint32_t def)
{
	struct mfi_pd_info info;
	static char buf[16];
	char *p;
	int error, fd, len;

	if ((def & MFI_DNAME_HONOR_OPTS) != 0 &&
	    (mfi_opts & (MFI_DNAME_ES|MFI_DNAME_DEVICE_ID)) != 0)
		def = mfi_opts & (MFI_DNAME_ES|MFI_DNAME_DEVICE_ID);

	buf[0] = '\0';
	if (pinfo == NULL && def & MFI_DNAME_ES) {
		/* Fallback in case of error, just ignore flags. */
		if (device_id == 0xffff)
			snprintf(buf, sizeof(buf), "MISSING");
		else
			snprintf(buf, sizeof(buf), "%2u", device_id);

		fd = mfi_open(mfi_unit);
		if (fd < 0) {
			warn("mfi_open");
			return (buf);
		}

		/* Get the info for this drive. */
		if (mfi_pd_get_info(fd, device_id, &info, NULL) < 0) {
			warn("Failed to fetch info for drive %2u", device_id);
			close(fd);
			return (buf);
		}

		close(fd);
		pinfo = &info;
	}

	p = buf;
	len = sizeof(buf);
	if (def & MFI_DNAME_DEVICE_ID) {
		if (device_id == 0xffff)
			error = snprintf(p, len, "MISSING");
		else
			error = snprintf(p, len, "%2u", device_id);
		if (error >= 0) {
			p += error;
			len -= error;
		}
	}
	if ((def & (MFI_DNAME_ES|MFI_DNAME_DEVICE_ID)) ==
	    (MFI_DNAME_ES|MFI_DNAME_DEVICE_ID) && len >= 2) {
		*p++ = ' ';
		len--;
		*p = '\0';
		len--;
	}
	if (def & MFI_DNAME_ES) {
		if (pinfo->encl_device_id == 0xffff)
			error = snprintf(p, len, "S%u",
			    pinfo->slot_number);
		else if (pinfo->encl_device_id == pinfo->ref.v.device_id)
			error = snprintf(p, len, "E%u",
			    pinfo->encl_index);
		else
			error = snprintf(p, len, "E%u:S%u",
			    pinfo->encl_index, pinfo->slot_number);
		if (error >= 0) {
			p += error;
			len -= error;
		}
	}

	return (buf);
}
Exemple #15
0
static int
add_spare(int ac, char **av)
{
	struct mfi_pd_info info;
	struct mfi_config_data *config;
	struct mfi_array *ar;
	struct mfi_ld_config *ld;
	struct mfi_spare *spare;
	uint16_t device_id;
	uint8_t target_id;
	char *p;
	int error, fd, i;

	if (ac < 2) {
		warnx("add spare: drive required");
		return (EINVAL);
	}

	fd = mfi_open(mfi_unit);
	if (fd < 0) {
		error = errno;
		warn("mfi_open");
		return (error);
	}

	config = NULL;
	spare = NULL;
	error = mfi_lookup_drive(fd, av[1], &device_id);
	if (error)
		goto error;

	if (mfi_pd_get_info(fd, device_id, &info, NULL) < 0) {
		error = errno;
		warn("Failed to fetch drive info");
		goto error;
	}

	if (info.fw_state != MFI_PD_STATE_UNCONFIGURED_GOOD) {
		warnx("Drive %u is not available", device_id);
		error = EINVAL;
		goto error;
	}

	if (ac > 2) {
		if (mfi_lookup_volume(fd, av[2], &target_id) < 0) {
			error = errno;
			warn("Invalid volume %s", av[2]);
			goto error;
		}
	}

	if (mfi_config_read(fd, &config) < 0) {
		error = errno;
		warn("Failed to read configuration");
		goto error;
	}

	spare = malloc(sizeof(struct mfi_spare) + sizeof(uint16_t) *
	    config->array_count);
	if (spare == NULL) {
		warnx("malloc failed");
		error = ENOMEM;
		goto error;
	}
	bzero(spare, sizeof(struct mfi_spare));
	spare->ref = info.ref;

	if (ac == 2) {
		/* Global spare backs all arrays. */
		p = (char *)config->array;
		for (i = 0; i < config->array_count; i++) {
			ar = (struct mfi_array *)p;
			if (ar->size > info.coerced_size) {
				warnx("Spare isn't large enough for array %u",
				    ar->array_ref);
				error = EINVAL;
				goto error;
			}
			p += config->array_size;
		}
		spare->array_count = 0;
	} else  {
		/*
		 * Dedicated spares only back the arrays for a
		 * specific volume.
		 */
		ld = mfi_config_lookup_volume(config, target_id);
		if (ld == NULL) {
			warnx("Did not find volume %d", target_id);
			error = EINVAL;
			goto error;
		}

		spare->spare_type |= MFI_SPARE_DEDICATED;
		spare->array_count = ld->params.span_depth;
		for (i = 0; i < ld->params.span_depth; i++) {
			ar = mfi_config_lookup_array(config,
			    ld->span[i].array_ref);
			if (ar == NULL) {
				warnx("Missing array; inconsistent config?");
				error = ENXIO;
				goto error;
			}
			if (ar->size > info.coerced_size) {
				warnx("Spare isn't large enough for array %u",
				    ar->array_ref);
				error = EINVAL;
				goto error;
			}				
			spare->array_ref[i] = ar->array_ref;
		}
	}

	if (mfi_dcmd_command(fd, MFI_DCMD_CFG_MAKE_SPARE, spare,
	    sizeof(struct mfi_spare) + sizeof(uint16_t) * spare->array_count,
	    NULL, 0, NULL) < 0) {
		error = errno;
		warn("Failed to assign spare");
		/* FALLTHROUGH. */
	}

error:
	free(spare);
	free(config);
	close(fd);

	return (error);
}
Exemple #16
0
static int
delete_volume(int ac, char **av)
{
	struct mfi_ld_info info;
	int error, fd;
	uint8_t target_id, mbox[4];

	/*
	 * Backwards compat.  Map 'delete volume' to 'delete' and
	 * 'delete spare' to 'remove'.
	 */
	if (ac > 1) {
		if (strcmp(av[1], "volume") == 0) {
			av++;
			ac--;
		} else if (strcmp(av[1], "spare") == 0) {
			av++;
			ac--;
			return (remove_spare(ac, av));
		}
	}

	if (ac != 2) {
		warnx("delete volume: volume required");
		return (EINVAL);
	}

	fd = mfi_open(mfi_unit);
	if (fd < 0) {
		error = errno;
		warn("mfi_open");
		return (error);
	}

	if (!mfi_reconfig_supported()) {
		warnx("The current mfi(4) driver does not support "
		    "configuration changes.");
		close(fd);
		return (EOPNOTSUPP);
	}

	if (mfi_lookup_volume(fd, av[1], &target_id) < 0) {
		error = errno;
		warn("Invalid volume %s", av[1]);
		close(fd);
		return (error);
	}

	if (mfi_ld_get_info(fd, target_id, &info, NULL) < 0) {
		error = errno;
		warn("Failed to get info for volume %d", target_id);
		close(fd);
		return (error);
	}

	if (mfi_volume_busy(fd, target_id)) {
		warnx("Volume %s is busy and cannot be deleted",
		    mfi_volume_name(fd, target_id));
		close(fd);
		return (EBUSY);
	}

	mbox_store_ldref(mbox, &info.ld_config.properties.ld);
	if (mfi_dcmd_command(fd, MFI_DCMD_LD_DELETE, NULL, 0, mbox,
	    sizeof(mbox), NULL) < 0) {
		error = errno;
		warn("Failed to delete volume");
		close(fd);
		return (error);
	}

	close(fd);

	return (0);
}
Exemple #17
0
static int
create_volume(int ac, char **av)
{
	struct mfi_config_data *config;
	struct mfi_array *ar;
	struct mfi_ld_config *ld;
	struct config_id_state state;
	size_t config_size;
	char *p, *cfg_arrays, *cfg_volumes;
	int error, fd, i, raid_type;
	int narrays, nvolumes, arrays_per_volume;
	struct array_info *arrays;
	long stripe_size;
#ifdef DEBUG
	int dump;
#endif
	int ch, verbose;

	/*
	 * Backwards compat.  Map 'create volume' to 'create' and
	 * 'create spare' to 'add'.
	 */
	if (ac > 1) {
		if (strcmp(av[1], "volume") == 0) {
			av++;
			ac--;
		} else if (strcmp(av[1], "spare") == 0) {
			av++;
			ac--;
			return (add_spare(ac, av));
		}
	}

	if (ac < 2) {
		warnx("create volume: volume type required");
		return (EINVAL);
	}

	bzero(&state, sizeof(state));
	config = NULL;
	arrays = NULL;
	narrays = 0;
	error = 0;

	fd = mfi_open(mfi_unit);
	if (fd < 0) {
		error = errno;
		warn("mfi_open");
		return (error);
	}

	if (!mfi_reconfig_supported()) {
		warnx("The current mfi(4) driver does not support "
		    "configuration changes.");
		error = EOPNOTSUPP;
		goto error;
	}

	/* Lookup the RAID type first. */
	raid_type = -1;
	for (i = 0; raid_type_table[i].name != NULL; i++)
		if (strcasecmp(raid_type_table[i].name, av[1]) == 0) {
			raid_type = raid_type_table[i].raid_type;
			break;
		}

	if (raid_type == -1) {
		warnx("Unknown or unsupported volume type %s", av[1]);
		error = EINVAL;
		goto error;
	}

	/* Parse any options. */
	optind = 2;
#ifdef DEBUG
	dump = 0;
#endif
	verbose = 0;
	stripe_size = 64 * 1024;

	while ((ch = getopt(ac, av, "ds:v")) != -1) {
		switch (ch) {
#ifdef DEBUG
		case 'd':
			dump = 1;
			break;
#endif
		case 's':
			stripe_size = dehumanize(optarg);
			if ((stripe_size < 512) || (!powerof2(stripe_size)))
				stripe_size = 64 * 1024;
			break;
		case 'v':
			verbose = 1;
			break;
		case '?':
		default:
			error = EINVAL;
			goto error;
		}
	}
	ac -= optind;
	av += optind;

	/* Parse all the arrays. */
	narrays = ac;
	if (narrays == 0) {
		warnx("At least one drive list is required");
		error = EINVAL;
		goto error;
	}
	switch (raid_type) {
	case RT_RAID0:
	case RT_RAID1:
	case RT_RAID5:
	case RT_RAID6:
	case RT_CONCAT:
		if (narrays != 1) {
			warnx("Only one drive list can be specified");
			error = EINVAL;
			goto error;
		}
		break;
	case RT_RAID10:
	case RT_RAID50:
	case RT_RAID60:
		if (narrays < 1) {
			warnx("RAID10, RAID50, and RAID60 require at least "
			    "two drive lists");
			error = EINVAL;
			goto error;
		}
		if (narrays > MFI_MAX_SPAN_DEPTH) {
			warnx("Volume spans more than %d arrays",
			    MFI_MAX_SPAN_DEPTH);
			error = EINVAL;
			goto error;
		}
		break;
	}
	arrays = calloc(narrays, sizeof(*arrays));
	if (arrays == NULL) {
		warnx("malloc failed");
		error = ENOMEM;
		goto error;
	}
	for (i = 0; i < narrays; i++) {
		error = parse_array(fd, raid_type, av[i], &arrays[i]);
		if (error)
			goto error;
	}

	switch (raid_type) {
	case RT_RAID10:
	case RT_RAID50:
	case RT_RAID60:
		for (i = 1; i < narrays; i++) {
			if (arrays[i].drive_count != arrays[0].drive_count) {
				warnx("All arrays must contain the same "
				    "number of drives");
				error = EINVAL;
				goto error;
			}
		}
		break;
	}

	/*
	 * Fetch the current config and build sorted lists of existing
	 * array and volume identifiers.
	 */
	if (mfi_config_read(fd, &config) < 0) {
		error = errno;
		warn("Failed to read configuration");
		goto error;
	}
	p = (char *)config->array;
	state.array_ref = 0xffff;
	state.target_id = 0xff;
	state.array_count = config->array_count;
	if (config->array_count > 0) {
		state.arrays = calloc(config->array_count, sizeof(int));
		if (state.arrays == NULL) {
			warnx("malloc failed");
			error = ENOMEM;
			goto error;
		}
		for (i = 0; i < config->array_count; i++) {
			ar = (struct mfi_array *)p;
			state.arrays[i] = ar->array_ref;
			p += config->array_size;
		}
		qsort(state.arrays, config->array_count, sizeof(int),
		    compare_int);
	} else
		state.arrays = NULL;
	state.log_drv_count = config->log_drv_count;
	if (config->log_drv_count) {
		state.volumes = calloc(config->log_drv_count, sizeof(int));
		if (state.volumes == NULL) {
			warnx("malloc failed");
			error = ENOMEM;
			goto error;
		}
		for (i = 0; i < config->log_drv_count; i++) {
			ld = (struct mfi_ld_config *)p;
			state.volumes[i] = ld->properties.ld.v.target_id;
			p += config->log_drv_size;
		}
		qsort(state.volumes, config->log_drv_count, sizeof(int),
		    compare_int);
	} else
		state.volumes = NULL;
	free(config);

	/* Determine the size of the configuration we will build. */
	switch (raid_type) {
	case RT_RAID0:
	case RT_RAID1:
	case RT_RAID5:
	case RT_RAID6:
	case RT_CONCAT:
	case RT_JBOD:
		/* Each volume spans a single array. */
		nvolumes = narrays;
		break;
	case RT_RAID10:
	case RT_RAID50:
	case RT_RAID60:
		/* A single volume spans multiple arrays. */
		nvolumes = 1;
		break;
	default:
		/* Pacify gcc. */
		abort();
	}

	config_size = sizeof(struct mfi_config_data) +
	    sizeof(struct mfi_ld_config) * nvolumes + MFI_ARRAY_SIZE * narrays;
	config = calloc(1, config_size);
	if (config == NULL) {
		warnx("malloc failed");
		error = ENOMEM;
		goto error;
	}
	config->size = config_size;
	config->array_count = narrays;
	config->array_size = MFI_ARRAY_SIZE;	/* XXX: Firmware hardcode */
	config->log_drv_count = nvolumes;
	config->log_drv_size = sizeof(struct mfi_ld_config);
	config->spares_count = 0;
	config->spares_size = 40;		/* XXX: Firmware hardcode */
	cfg_arrays = (char *)config->array;
	cfg_volumes = cfg_arrays + config->array_size * narrays;

	/* Build the arrays. */
	for (i = 0; i < narrays; i++) {
		build_array(fd, cfg_arrays, &arrays[i], &state, verbose);
		cfg_arrays += config->array_size;
	}

	/* Now build the volume(s). */
	arrays_per_volume = narrays / nvolumes;
	for (i = 0; i < nvolumes; i++) {
		build_volume(cfg_volumes, arrays_per_volume,
		    &arrays[i * arrays_per_volume], raid_type, stripe_size,
		    &state, verbose);
		cfg_volumes += config->log_drv_size;
	}

#ifdef DEBUG
	if (dump)
		dump_config(fd, config);
#endif

	/* Send the new config to the controller. */
	if (mfi_dcmd_command(fd, MFI_DCMD_CFG_ADD, config, config_size,
	    NULL, 0, NULL) < 0) {
		error = errno;
		warn("Failed to add volume");
		/* FALLTHROUGH */
	}

error:
	/* Clean up. */
	free(config);
	free(state.volumes);
	free(state.arrays);
	for (i = 0; i < narrays; i++)
		free(arrays[i].drives);
	free(arrays);
	close(fd);

	return (error);
}
Exemple #18
0
static int
flash_adapter(int ac, char **av)
{
	struct mfi_progress dummy;
	off_t offset;
	size_t nread;
	char *buf;
	struct stat sb;
	int error, fd, flash;
	uint8_t mbox[4], status;

	if (ac != 2) {
		warnx("flash: Firmware file required");
		return (EINVAL);
	}

	flash = open(av[1], O_RDONLY);
	if (flash < 0) {
		error = errno;
		warn("flash: Failed to open %s", av[1]);
		return (error);
	}

	buf = NULL;
	fd = -1;

	if (fstat(flash, &sb) < 0) {
		error = errno;
		warn("fstat(%s)", av[1]);
		goto error;
	}
	if (sb.st_size % 1024 != 0 || sb.st_size > 0x7fffffff) {
		warnx("Invalid flash file size");
		error = EINVAL;
		goto error;
	}

	fd = mfi_open(mfi_unit, O_RDWR);
	if (fd < 0) {
		error = errno;
		warn("mfi_open");
		goto error;
	}

	/* First, ask the firmware to allocate space for the flash file. */
	mbox_store_word(mbox, sb.st_size);
	mfi_dcmd_command(fd, MFI_DCMD_FLASH_FW_OPEN, NULL, 0, mbox, 4, &status);
	if (status != MFI_STAT_OK) {
		warnx("Failed to alloc flash memory: %s", mfi_status(status));
		error = EIO;
		goto error;
	}

	/* Upload the file 64k at a time. */
	buf = malloc(FLASH_BUF_SIZE);
	if (buf == NULL) {
		warnx("malloc failed");
		error = ENOMEM;
		goto error;
	}
	offset = 0;
	while (sb.st_size > 0) {
		nread = read(flash, buf, FLASH_BUF_SIZE);
		if (nread <= 0 || nread % 1024 != 0) {
			warnx("Bad read from flash file");
			mfi_dcmd_command(fd, MFI_DCMD_FLASH_FW_CLOSE, NULL, 0,
			    NULL, 0, NULL);
			error = ENXIO;
			goto error;
		}

		mbox_store_word(mbox, offset);
		mfi_dcmd_command(fd, MFI_DCMD_FLASH_FW_DOWNLOAD, buf, nread,
		    mbox, 4, &status);
		if (status != MFI_STAT_OK) {
			warnx("Flash download failed: %s", mfi_status(status));
			mfi_dcmd_command(fd, MFI_DCMD_FLASH_FW_CLOSE, NULL, 0,
			    NULL, 0, NULL);
			error = ENXIO;
			goto error;
		}
		sb.st_size -= nread;
		offset += nread;
	}

	/* Kick off the flash. */
	printf("WARNING: Firmware flash in progress, do not reboot machine... ");
	fflush(stdout);
	mfi_dcmd_command(fd, MFI_DCMD_FLASH_FW_FLASH, &dummy, sizeof(dummy),
	    NULL, 0, &status);
	if (status != MFI_STAT_OK) {
		printf("failed:\n\t%s\n", mfi_status(status));
		error = ENXIO;
		goto error;
	}
	printf("finished\n");
	error = display_pending_firmware(fd);

error:
	free(buf);
	if (fd >= 0)
		close(fd);
	close(flash);

	return (error);
}
Exemple #19
0
static int
show_patrol(int ac, char **av)
{
    struct mfi_pr_properties prop;
    struct mfi_pr_status status;
    struct mfi_pd_list *list;
    struct mfi_pd_info info;
    char label[24];
    time_t now;
    uint32_t at;
    int error, fd;
    u_int i;

    fd = mfi_open(mfi_unit);
    if (fd < 0) {
        error = errno;
        warn("mfi_open");
        return (error);
    }

    time(&now);
    mfi_get_time(fd, &at);
    error = patrol_get_props(fd, &prop);
    if (error) {
        close(fd);
        return (error);
    }
    printf("Operation Mode: ");
    switch (prop.op_mode) {
    case MFI_PR_OPMODE_AUTO:
        printf("auto\n");
        break;
    case MFI_PR_OPMODE_MANUAL:
        printf("manual\n");
        break;
    case MFI_PR_OPMODE_DISABLED:
        printf("disabled\n");
        break;
    default:
        printf("??? (%02x)\n", prop.op_mode);
        break;
    }
    if (prop.op_mode == MFI_PR_OPMODE_AUTO) {
        if (at != 0 && prop.next_exec)
            printf("    Next Run Starts: %s", adapter_time(now, at,
                    prop.next_exec));
        if (prop.exec_freq == 0xffffffff)
            printf("    Runs Execute Continuously\n");
        else if (prop.exec_freq != 0)
            printf("    Runs Start Every %u seconds\n",
                   prop.exec_freq);
    }

    if (mfi_dcmd_command(fd, MFI_DCMD_PR_GET_STATUS, &status,
                         sizeof(status), NULL, 0, NULL) < 0) {
        error = errno;
        warn("Failed to get patrol read properties");
        close(fd);
        return (error);
    }
    printf("Runs Completed: %u\n", status.num_iteration);
    printf("Current State: ");
    switch (status.state) {
    case MFI_PR_STATE_STOPPED:
        printf("stopped\n");
        break;
    case MFI_PR_STATE_READY:
        printf("ready\n");
        break;
    case MFI_PR_STATE_ACTIVE:
        printf("active\n");
        break;
    case MFI_PR_STATE_ABORTED:
        printf("aborted\n");
        break;
    default:
        printf("??? (%02x)\n", status.state);
        break;
    }
    if (status.state == MFI_PR_STATE_ACTIVE) {
        if (mfi_pd_get_list(fd, &list, NULL) < 0) {
            error = errno;
            warn("Failed to get drive list");
            close(fd);
            return (error);
        }

        for (i = 0; i < list->count; i++) {
            if (list->addr[i].scsi_dev_type != 0)
                continue;

            if (mfi_pd_get_info(fd, list->addr[i].device_id, &info,
                                NULL) < 0) {
                error = errno;
                warn("Failed to fetch info for drive %u",
                     list->addr[i].device_id);
                free(list);
                close(fd);
                return (error);
            }
            if (info.prog_info.active & MFI_PD_PROGRESS_PATROL) {
                snprintf(label, sizeof(label), "    Drive %s",
                         mfi_drive_name(NULL,
                                        list->addr[i].device_id,
                                        MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS));
                mfi_display_progress(label,
                                     &info.prog_info.patrol);
            }
        }
        free(list);
    }

    close(fd);

    return (0);
}
Exemple #20
0
static int
patrol_config(int ac, char **av)
{
    struct mfi_pr_properties prop;
    long val;
    time_t now;
    int error, fd;
    uint32_t at, next_exec, exec_freq;
    char *cp;
    uint8_t op_mode;

    exec_freq = 0;	/* GCC too stupid */
    next_exec = 0;
    if (ac < 2) {
        warnx("patrol: command required");
        return (EINVAL);
    }
    if (strcasecmp(av[1], "auto") == 0) {
        op_mode = MFI_PR_OPMODE_AUTO;
        if (ac > 2) {
            if (strcasecmp(av[2], "continuously") == 0)
                exec_freq = 0xffffffff;
            else {
                val = strtol(av[2], &cp, 0);
                if (*cp != '\0') {
                    warnx("patrol: Invalid interval %s",
                          av[2]);
                    return (EINVAL);
                }
                exec_freq = val;
            }
        }
        if (ac > 3) {
            val = strtol(av[3], &cp, 0);
            if (*cp != '\0' || val < 0) {
                warnx("patrol: Invalid start time %s", av[3]);
                return (EINVAL);
            }
            next_exec = val;
        }
    } else if (strcasecmp(av[1], "manual") == 0)
        op_mode = MFI_PR_OPMODE_MANUAL;
    else if (strcasecmp(av[1], "disable") == 0)
        op_mode = MFI_PR_OPMODE_DISABLED;
    else {
        warnx("patrol: Invalid command %s", av[1]);
        return (EINVAL);
    }

    fd = mfi_open(mfi_unit);
    if (fd < 0) {
        error = errno;
        warn("mfi_open");
        return (error);
    }

    error = patrol_get_props(fd, &prop);
    if (error) {
        close(fd);
        return (error);
    }
    prop.op_mode = op_mode;
    if (op_mode == MFI_PR_OPMODE_AUTO) {
        if (ac > 2)
            prop.exec_freq = exec_freq;
        if (ac > 3) {
            time(&now);
            mfi_get_time(fd, &at);
            if (at == 0) {
                close(fd);
                return (ENXIO);
            }
            prop.next_exec = at + next_exec;
            printf("Starting next patrol read at %s",
                   adapter_time(now, at, prop.next_exec));
        }
    }
    if (mfi_dcmd_command(fd, MFI_DCMD_PR_SET_PROPERTIES, &prop,
                         sizeof(prop), NULL, 0, NULL) < 0) {
        error = errno;
        warn("Failed to set patrol read properties");
        close(fd);
        return (error);
    }

    close(fd);

    return (0);
}