示例#1
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);
}
示例#2
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);
}
示例#3
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);
}
示例#4
0
/* Parse a comma-separated list of drives for an array. */
static int
parse_array(int fd, int raid_type, char *array_str, struct array_info *info)
{
	struct mfi_pd_info *pinfo;
	uint16_t device_id;
	char *cp;
	u_int count;
	int error;

	cp = array_str;
	for (count = 0; cp != NULL; count++) {
		cp = strchr(cp, ',');
		if (cp != NULL) {
			cp++;
			if (*cp == ',') {
				warnx("Invalid drive list '%s'", array_str);
				return (EINVAL);
			}
		}
	}

	/* Validate the number of drives for this array. */
	if (count >= MAX_DRIVES_PER_ARRAY) {
		warnx("Too many drives for a single array: max is %zu",
		    MAX_DRIVES_PER_ARRAY);
		return (EINVAL);
	}
	switch (raid_type) {
	case RT_RAID1:
	case RT_RAID10:
		if (count % 2 != 0) {
			warnx("RAID1 and RAID10 require an even number of "
			    "drives in each array");
			return (EINVAL);
		}
		break;
	case RT_RAID5:
	case RT_RAID50:
		if (count < 3) {
			warnx("RAID5 and RAID50 require at least 3 drives in "
			    "each array");
			return (EINVAL);
		}
		break;
	case RT_RAID6:
	case RT_RAID60:
		if (count < 4) {
			warnx("RAID6 and RAID60 require at least 4 drives in "
			    "each array");
			return (EINVAL);
		}
		break;
	}

	/* Validate each drive. */
	info->drives = calloc(count, sizeof(struct mfi_pd_info));
	if (info->drives == NULL) {
		warnx("malloc failed");
		return (ENOMEM);
	}
	info->drive_count = count;
	for (pinfo = info->drives; (cp = strsep(&array_str, ",")) != NULL;
	     pinfo++) {
		error = mfi_lookup_drive(fd, cp, &device_id);
		if (error) {
			free(info->drives);
			return (error);
		}

		if (mfi_pd_get_info(fd, device_id, pinfo, NULL) < 0) {
			error = errno;
			warn("Failed to fetch drive info for drive %s", cp);
			free(info->drives);
			return (error);
		}

		if (pinfo->fw_state != MFI_PD_STATE_UNCONFIGURED_GOOD) {
			warnx("Drive %u is not available", device_id);
			free(info->drives);
			return (EINVAL);
		}
	}

	return (0);
}
示例#5
0
/* Display raw data about a config. */
static void
dump_config(int fd, struct mfi_config_data *config)
{
	struct mfi_array *ar;
	struct mfi_ld_config *ld;
	struct mfi_spare *sp;
	struct mfi_pd_info pinfo;
	uint16_t device_id;
	char *p;
	int i, j;

	printf(
	    "mfi%d Configuration (Debug): %d arrays, %d volumes, %d spares\n",
	    mfi_unit, config->array_count, config->log_drv_count,
	    config->spares_count);
	printf("  array size: %u\n", config->array_size);
	printf("  volume size: %u\n", config->log_drv_size);
	printf("  spare size: %u\n", config->spares_size);
	p = (char *)config->array;

	for (i = 0; i < config->array_count; i++) {
		ar = (struct mfi_array *)p;
		printf("    array %u of %u drives:\n", ar->array_ref,
		    ar->num_drives);
		printf("      size = %ju\n", (uintmax_t)ar->size);
		for (j = 0; j < ar->num_drives; j++) {
			device_id = ar->pd[j].ref.v.device_id;
			if (device_id == 0xffff)
				printf("        drive MISSING\n");
			else {
				printf("        drive %u %s\n", device_id,
				    mfi_pdstate(ar->pd[j].fw_state));
				if (mfi_pd_get_info(fd, device_id, &pinfo,
				    NULL) >= 0) {
					printf("          raw size: %ju\n",
					    (uintmax_t)pinfo.raw_size);
					printf("          non-coerced size: %ju\n",
					    (uintmax_t)pinfo.non_coerced_size);
					printf("          coerced size: %ju\n",
					    (uintmax_t)pinfo.coerced_size);
				}
			}
		}
		p += config->array_size;
	}

	for (i = 0; i < config->log_drv_count; i++) {
		ld = (struct mfi_ld_config *)p;
		printf("    volume %s ",
		    mfi_volume_name(fd, ld->properties.ld.v.target_id));
		printf("%s %s",
		    mfi_raid_level(ld->params.primary_raid_level,
			ld->params.secondary_raid_level),
		    mfi_ldstate(ld->params.state));
		if (ld->properties.name[0] != '\0')
			printf(" <%s>", ld->properties.name);
		printf("\n");
		printf("      primary raid level: %u\n",
		    ld->params.primary_raid_level);
		printf("      raid level qualifier: %u\n",
		    ld->params.raid_level_qualifier);
		printf("      secondary raid level: %u\n",
		    ld->params.secondary_raid_level);
		printf("      stripe size: %u\n", ld->params.stripe_size);
		printf("      num drives: %u\n", ld->params.num_drives);
		printf("      init state: %u\n", ld->params.init_state);
		printf("      consistent: %u\n", ld->params.is_consistent);
		printf("      no bgi: %u\n", ld->properties.no_bgi);
		printf("      spans:\n");
		for (j = 0; j < ld->params.span_depth; j++) {
			printf("        array %u @ ", ld->span[j].array_ref);
			printf("%ju : %ju\n",
			    (uintmax_t)ld->span[j].start_block,
			    (uintmax_t)ld->span[j].num_blocks);
		}
		p += config->log_drv_size;
	}

	for (i = 0; i < config->spares_count; i++) {
		sp = (struct mfi_spare *)p;
		printf("    %s spare %u ",
		    sp->spare_type & MFI_SPARE_DEDICATED ? "dedicated" :
		    "global", sp->ref.v.device_id);
		printf("%s", mfi_pdstate(MFI_PD_STATE_HOT_SPARE));
		printf(" backs:\n");
		for (j = 0; j < sp->array_count; j++)
			printf("        array %u\n", sp->array_ref[j]);
		p += config->spares_size;
	}
}
示例#6
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);
}