/* * There are several ways to enumerate physical disks. Unfortunately, * none of them are truly complete, so we have to build a union of all of * them. Specifically: * * - IOC2 : This gives us a list of volumes, and by walking the volumes we * can enumerate all of the drives attached to volumes including * online drives and failed drives. * - IOC3 : This gives us a list of all online physical drives including * drives that are not part of a volume nor a spare drive. It * does not include any failed drives. * - IOC5 : This gives us a list of all spare drives including failed * spares. * * The specific edge cases are that 1) a failed volume member can only be * found via IOC2, 2) a drive that is neither a volume member nor a spare * can only be found via IOC3, and 3) a failed spare can only be found via * IOC5. * * To handle this, walk all of the three lists and use the following * routine to add each drive encountered. It quietly succeeds if the * drive is already present in the list. It also sorts the list as it * inserts new drives. */ static int mpt_pd_insert(int fd, struct mpt_drive_list *list, U8 PhysDiskNum) { int i, j; /* * First, do a simple linear search to see if we have already * seen this drive. */ for (i = 0; i < list->ndrives; i++) { if (list->drives[i]->PhysDiskNum == PhysDiskNum) return (0); if (list->drives[i]->PhysDiskNum > PhysDiskNum) break; } /* * 'i' is our slot for the 'new' drive. Make room and then * read the drive info. */ for (j = list->ndrives - 1; j >= i; j--) list->drives[j + 1] = list->drives[j]; list->drives[i] = mpt_pd_info(fd, PhysDiskNum, NULL); if (list->drives[i] == NULL) return (errno); list->ndrives++; return (0); }
/* Helper function to set a drive to a given state. */ static int drive_set_state(char *drive, U8 Action, U8 State, const char *name) { CONFIG_PAGE_RAID_PHYS_DISK_0 *info; struct mpt_drive_list *list; U8 PhysDiskNum; int error, fd; fd = mpt_open(mpt_unit); if (fd < 0) { error = errno; warn("mpt_open"); return (error); } list = mpt_pd_list(fd); if (list == NULL) { close(fd); return (errno); } if (mpt_lookup_drive(list, drive, &PhysDiskNum) < 0) { error = errno; warn("Failed to find drive %s", drive); close(fd); return (error); } mpt_free_pd_list(list); /* Get the info for this drive. */ info = mpt_pd_info(fd, PhysDiskNum, NULL); if (info == NULL) { error = errno; warn("Failed to fetch info for drive %u", PhysDiskNum); close(fd); return (error); } /* Try to change the state. */ if (info->PhysDiskStatus.State == State) { warnx("Drive %u is already in the desired state", PhysDiskNum); free(info); close(fd); return (EINVAL); } error = mpt_raid_action(fd, Action, 0, 0, PhysDiskNum, 0, NULL, 0, NULL, NULL, 0, NULL, NULL, 0); if (error) { warnc(error, "Failed to set drive %u to %s", PhysDiskNum, name); free(info); close(fd); return (error); } free(info); close(fd); return (0); }
static int show_physdisks(int ac, char **av) { CONFIG_PAGE_RAID_PHYS_DISK_0 *pinfo; U16 IOCStatus; int error, fd, i; if (ac != 1) { warnx("show drives: extra arguments"); return (EINVAL); } fd = mpt_open(mpt_unit); if (fd < 0) { error = errno; warn("mpt_open"); return (error); } /* Try to find each possible phys disk page. */ for (i = 0; i <= 0xff; i++) { pinfo = mpt_pd_info(fd, i, &IOCStatus); if (pinfo == NULL) { if ((IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_CONFIG_INVALID_PAGE) warnx("mpt_pd_info(%d): %s", i, mpt_ioc_status(IOCStatus)); continue; } printf("%3u ", i); print_pd(pinfo, -1, 1); printf("\n"); } close(fd); return (0); }
static int show_config(int ac, char **av) { CONFIG_PAGE_IOC_2 *ioc2; CONFIG_PAGE_IOC_2_RAID_VOL *vol; CONFIG_PAGE_IOC_5 *ioc5; IOC_5_HOT_SPARE *spare; CONFIG_PAGE_RAID_VOL_0 *vinfo; RAID_VOL0_PHYS_DISK *disk; CONFIG_PAGE_RAID_VOL_1 *vnames; CONFIG_PAGE_RAID_PHYS_DISK_0 *pinfo; struct mpt_standalone_disk *sdisks; int error, fd, i, j, nsdisks; if (ac != 1) { warnx("show config: extra arguments"); return (EINVAL); } fd = mpt_open(mpt_unit); if (fd < 0) { error = errno; warn("mpt_open"); return (error); } /* Get the config from the controller. */ ioc2 = mpt_read_ioc_page(fd, 2, NULL); ioc5 = mpt_read_ioc_page(fd, 5, NULL); if (ioc2 == NULL || ioc5 == NULL) { error = errno; warn("Failed to get config"); return (error); } if (mpt_fetch_disks(fd, &nsdisks, &sdisks) < 0) { error = errno; warn("Failed to get standalone drive list"); return (error); } /* Dump out the configuration. */ printf("mpt%d Configuration: %d volumes, %d drives\n", mpt_unit, ioc2->NumActiveVolumes, ioc2->NumActivePhysDisks + nsdisks); vol = ioc2->RaidVolume; for (i = 0; i < ioc2->NumActiveVolumes; vol++, i++) { printf(" volume %s ", mpt_volume_name(vol->VolumeBus, vol->VolumeID)); vinfo = mpt_vol_info(fd, vol->VolumeBus, vol->VolumeID, NULL); if (vinfo == NULL) { printf("%s UNKNOWN", mpt_raid_level(vol->VolumeType)); } else print_vol(vinfo, -1); vnames = mpt_vol_names(fd, vol->VolumeBus, vol->VolumeID, NULL); if (vnames != NULL) { if (vnames->Name[0] != '\0') printf(" <%s>", vnames->Name); free(vnames); } if (vinfo == NULL) { printf("\n"); continue; } printf(" spans:\n"); disk = vinfo->PhysDisk; for (j = 0; j < vinfo->NumPhysDisks; disk++, j++) { printf(" drive %u ", disk->PhysDiskNum); pinfo = mpt_pd_info(fd, disk->PhysDiskNum, NULL); if (pinfo != NULL) { print_pd(pinfo, -1, 0); free(pinfo); } printf("\n"); } if (vinfo->VolumeSettings.HotSparePool != 0) { printf(" spare pools: "); print_spare_pools(vinfo->VolumeSettings.HotSparePool); printf("\n"); } free(vinfo); } spare = ioc5->HotSpare; for (i = 0; i < ioc5->NumHotSpares; spare++, i++) { printf(" spare %u ", spare->PhysDiskNum); pinfo = mpt_pd_info(fd, spare->PhysDiskNum, NULL); if (pinfo != NULL) { print_pd(pinfo, -1, 0); free(pinfo); } printf(" backs pool %d\n", ffs(spare->HotSparePool) - 1); } for (i = 0; i < nsdisks; i++) { printf(" drive %s ", sdisks[i].devname); print_standalone(&sdisks[i], -1, 0); printf("\n"); } free(ioc2); free(ioc5); free(sdisks); close(fd); return (0); }