diff --git a/iprconfig.c b/iprconfig.c index 3abfd72..97d32ee 100644 --- a/iprconfig.c +++ b/iprconfig.c @@ -15622,6 +15622,23 @@ static int set_ioa_caching(char **args, int num_args) return rc; } +/** + * get_live_dump - + * @args: argument vector + * @num_args: number of arguments + * + * Returns: + * 0 if success / non-zero on failure + **/ +static int get_live_dump (char **args, int num_args) +{ + struct ipr_dev *dev = find_gen_dev(args[0]); + + if (dev) + return ipr_get_live_dump(dev->ioa); + return -ENXIO; +} + static const struct { char *cmd; int min_args; @@ -15721,6 +15738,7 @@ static const struct { { "set-bus-speed", 3, 0, 3, set_bus_speed, "sg5 0 320" }, { "set-bus-width", 3, 0, 3, set_bus_width, "sg5 0 16" }, { "raid-migrate", 3, 1, 0, raid_migrate_cmd, "-r 10 [-s 256] sda sg6 sg7" }, + { "get-live-dump", 1, 0, 1, get_live_dump, "sg5" }, }; /** diff --git a/iprdump.c b/iprdump.c index 42debfe..0c150f5 100644 --- a/iprdump.c +++ b/iprdump.c @@ -20,7 +20,6 @@ #include #define IPRDUMP_SIZE (8 * 1024 * 1024) -#define IPRDUMP_DIR "/var/log/" #define MAX_DUMP_FILES 4 #define TOOL_NAME "iprdump" #define DUMP_PREFIX TOOL_NAME"." diff --git a/iprlib.c b/iprlib.c index 077e837..c554159 100644 --- a/iprlib.c +++ b/iprlib.c @@ -3869,6 +3869,159 @@ int ipr_query_res_redundancy_info(struct ipr_dev *dev, return rc; } +/** + * get_livedump_fname - + * @ioa: ipr_ioa struct + * @fname: string to return the filename + * @max: max size of fname + * + * Returns: + * negative on failure / otherwise length of the file name + * + **/ +static int get_livedump_fname(struct ipr_ioa *ioa, char *fname, int max) +{ + time_t cur_time, rc; + struct tm *cur_tm; + char time_str[100]; + int len; + + fname[0] = '\0'; + rc = time(&cur_time); + if (rc == ((time_t)-1)) + return -EIO; + + cur_tm = localtime(&cur_time); + if (!cur_tm) + return -EIO; + strftime(time_str, sizeof(time_str), "%Y%m%d.%H%M", cur_tm); + + len = snprintf(fname, max, "ipr-%04X-%s-dump-%s", ioa->ccin, + ioa->pci_address, time_str); + + return len; +} + +#define IPR_MAX_LIVE_DUMP_SIZE (16 * 1024 * 1024) + +/** + * get_scsi_max_xfer_len - + * @fd: IOA sg file descriptor + * + * Returns: + * 0 on failure / otherwise max scatter-gather transfer length + * + **/ +static int get_scsi_max_xfer_len(int fd) +{ + int rc, max_tablesize, max_scsi_len; + struct sysfs_module *sysfs_module; + struct sysfs_attribute *sysfs_attr; + + sysfs_module = sysfs_open_module("sg"); + if (!sysfs_module) { + syslog_dbg("Failed to open sg module. %m\n"); + return 0; + } + + sysfs_attr = sysfs_get_module_parm(sysfs_module, "scatter_elem_sz"); + if (!sysfs_attr) { + syslog_dbg("Failed to open scatter_elem_sz parameter from sg module. %m\n"); + return 0; + } + + rc = ioctl(fd, SG_GET_SG_TABLESIZE, &max_tablesize); + if (rc) { + syslog_dbg("Unable to get device scatter-gather table size. %m\n"); + return 0; + } + + max_scsi_len = max_tablesize * atoi(sysfs_attr->value); + + if (max_scsi_len < IPR_MAX_LIVE_DUMP_SIZE) + return max_scsi_len; + else + return IPR_MAX_LIVE_DUMP_SIZE; +} + +/** + * ipr_get_live_dump - + * @dev: ipr dev struct + * @info: ipr_res_redundancy_info struct + * + * Returns: + * 0 if success / non-zero on failure + * + **/ +int ipr_get_live_dump(struct ipr_ioa *ioa) +{ + char *name = ioa->ioa.gen_name; + struct sense_data_t sense_data; + u8 cdb[IPR_CCB_CDB_LEN], *buf; + char dump_file[100], dump_path[100]; + int rc, fd, fd_dump, buff_len; + + if (strlen(name) == 0) + return -ENOENT; + + fd = open(name, O_RDWR); + if (fd <= 1) { + if (!strcmp(tool_name, "iprconfig") || ipr_debug) + syslog(LOG_ERR, "Could not open %s. %m\n", name); + return errno; + } + + buff_len = get_scsi_max_xfer_len(fd); + if (buff_len == 0) { + rc = -EPERM; + goto out; + } + + memset(cdb, 0, IPR_CCB_CDB_LEN); + cdb[0] = IPR_IOA_SERVICE_ACTION; + cdb[1] = IPR_LIVE_DUMP; + cdb[10] = buff_len >> 24; + cdb[11] = (buff_len >> 16) & 0xff; + cdb[12] = (buff_len >> 8) & 0xff; + cdb[13] = buff_len & 0xff; + + buf = (u8*) malloc(buff_len); + + rc = sg_ioctl(fd, cdb, buf, buff_len, SG_DXFER_FROM_DEV, + &sense_data, IPR_INTERNAL_DEV_TIMEOUT); + + if (rc) { + ioa_cmd_err(ioa, &sense_data, "Live Dump", rc); + goto out_free; + } + + rc = get_livedump_fname(ioa, dump_file, sizeof(dump_file)); + if (rc < 0) { + syslog_dbg("Failed to create a live dump file name.\n"); + goto out_free; + } + + snprintf(dump_path, sizeof(dump_path), "%s%s", IPRDUMP_DIR, dump_file); + fd_dump = creat(dump_path, S_IRUSR); + if (fd_dump < 0) { + syslog(LOG_ERR, "Could not open %s. %m\n", dump_path); + rc = fd_dump; + goto out_free; + } + + rc = write(fd_dump, buf, buff_len); + if (rc != buff_len) + syslog(LOG_ERR, "Could not write dump on file %s. %m\n", dump_path); + + close(fd_dump); + +out_free: + free(buf); +out: + close(fd); + return rc; +} + /** * ipr_set_array_asym_access - * @dev: ipr_dev struct diff --git a/iprlib.h b/iprlib.h index 7cff2cf..a3e0b3e 100644 --- a/iprlib.h +++ b/iprlib.h @@ -64,6 +64,8 @@ #define FIRMWARE_HOTPLUG_CONFIG_FILE "/etc/hotplug/firmware.agent" #define FIRMWARE_HOTPLUG_DEFAULT_DIR LINUX_UCODE_BASE_DIR +#define IPRDUMP_DIR "/var/log/" + #define IPR_JBOD_BLOCK_SIZE 512 #define IPR_DEFAULT_AF_BLOCK_SIZE 522 #define IOCTL_BUFFER_SIZE 512 @@ -150,6 +152,7 @@ #define IPR_QUERY_RES_REDUNDANCY_INFO 0x13 #define IPR_CHANGE_CACHE_PARAMETERS 0x14 #define IPR_QUERY_CACHE_PARAMETERS 0x16 +#define IPR_LIVE_DUMP 0x31 #define IPR_EVALUATE_DEVICE 0xE4 #define SKIP_READ 0xE8 #define SKIP_WRITE 0xEA @@ -2332,6 +2335,7 @@ int ipr_get_blk_size(struct ipr_dev *); u32 get_ioa_ucode_version(char *); int ipr_improper_device_type(struct ipr_dev *); int ipr_get_fw_version(struct ipr_dev *, u8 release_level[4]); +int ipr_get_live_dump(struct ipr_ioa *); static inline u32 ipr_get_dev_res_handle(struct ipr_ioa *ioa, struct ipr_dev_record *dev_rcd) {