From afc3f83cb4a5bb3c8f18380bdeca6b65a6ff9543 Mon Sep 17 00:00:00 2001 From: Brian King Date: Wed, 24 Aug 2016 12:56:51 -0500 Subject: scsi: ipr: Add asynchronous error notification This patch implements functions for pushing HCAM (host controlled asynchronous messages) error buffers to userspace through sysfs attributes. Reads to the "async_err_log" attribute will result in a single HCAM buffer being copied to userspace; one can process the next HCAM buffer by writing any string to the same attribute. A new list was added to the ioa_cfg structure to store the HCAM buffers for later reporting. We also send a KOBJ_CHANGE event whenever a new HCAM buffer is made available to userspace. Signed-off-by: Heitor Ricardo Alves de Siqueira Signed-off-by: Gabriel Krisman Bertazi Signed-off-by: Brian King Signed-off-by: Martin K. Petersen --- drivers/scsi/ipr.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 113 insertions(+), 12 deletions(-) (limited to 'drivers/scsi/ipr.c') diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index bf85974be862..5ecc32cecd10 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -1473,7 +1473,7 @@ static void ipr_process_ccn(struct ipr_cmnd *ipr_cmd) struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb; u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc); - list_del(&hostrcb->queue); + list_del_init(&hostrcb->queue); list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); if (ioasc) { @@ -2552,6 +2552,23 @@ static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg, } } +static struct ipr_hostrcb *ipr_get_free_hostrcb(struct ipr_ioa_cfg *ioa) +{ + struct ipr_hostrcb *hostrcb; + + hostrcb = list_first_entry_or_null(&ioa->hostrcb_free_q, + struct ipr_hostrcb, queue); + + if (unlikely(!hostrcb)) { + dev_info(&ioa->pdev->dev, "Reclaiming async error buffers."); + hostrcb = list_first_entry_or_null(&ioa->hostrcb_report_q, + struct ipr_hostrcb, queue); + } + + list_del_init(&hostrcb->queue); + return hostrcb; +} + /** * ipr_process_error - Op done function for an adapter error log. * @ipr_cmd: ipr command struct @@ -2569,13 +2586,14 @@ static void ipr_process_error(struct ipr_cmnd *ipr_cmd) struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb; u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc); u32 fd_ioasc; + char *envp[] = { "ASYNC_ERR_LOG=1", NULL }; if (ioa_cfg->sis64) fd_ioasc = be32_to_cpu(hostrcb->hcam.u.error64.fd_ioasc); else fd_ioasc = be32_to_cpu(hostrcb->hcam.u.error.fd_ioasc); - list_del(&hostrcb->queue); + list_del_init(&hostrcb->queue); list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); if (!ioasc) { @@ -2588,6 +2606,10 @@ static void ipr_process_error(struct ipr_cmnd *ipr_cmd) "Host RCB failed with IOASC: 0x%08X\n", ioasc); } + list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_report_q); + hostrcb = ipr_get_free_hostrcb(ioa_cfg); + kobject_uevent_env(&ioa_cfg->host->shost_dev.kobj, KOBJ_CHANGE, envp); + ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_LOG_DATA, hostrcb); } @@ -4095,6 +4117,64 @@ static struct device_attribute ipr_ioa_fw_type_attr = { .show = ipr_show_fw_type }; +static ssize_t ipr_read_async_err_log(struct file *filep, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, + loff_t off, size_t count) +{ + struct device *cdev = container_of(kobj, struct device, kobj); + struct Scsi_Host *shost = class_to_shost(cdev); + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; + struct ipr_hostrcb *hostrcb; + unsigned long lock_flags = 0; + int ret; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + hostrcb = list_first_entry_or_null(&ioa_cfg->hostrcb_report_q, + struct ipr_hostrcb, queue); + if (!hostrcb) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return 0; + } + ret = memory_read_from_buffer(buf, count, &off, &hostrcb->hcam, + sizeof(hostrcb->hcam)); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return ret; +} + +static ssize_t ipr_next_async_err_log(struct file *filep, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, + loff_t off, size_t count) +{ + struct device *cdev = container_of(kobj, struct device, kobj); + struct Scsi_Host *shost = class_to_shost(cdev); + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; + struct ipr_hostrcb *hostrcb; + unsigned long lock_flags = 0; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + hostrcb = list_first_entry_or_null(&ioa_cfg->hostrcb_report_q, + struct ipr_hostrcb, queue); + if (!hostrcb) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return count; + } + + /* Reclaim hostrcb before exit */ + list_move_tail(&hostrcb->queue, &ioa_cfg->hostrcb_free_q); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return count; +} + +static struct bin_attribute ipr_ioa_async_err_log = { + .attr = { + .name = "async_err_log", + .mode = S_IRUGO | S_IWUSR, + }, + .size = 0, + .read = ipr_read_async_err_log, + .write = ipr_next_async_err_log +}; + static struct device_attribute *ipr_ioa_attrs[] = { &ipr_fw_version_attr, &ipr_log_level_attr, @@ -7026,8 +7106,7 @@ static int ipr_ioa_reset_done(struct ipr_cmnd *ipr_cmd) { struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; struct ipr_resource_entry *res; - struct ipr_hostrcb *hostrcb, *temp; - int i = 0, j; + int j; ENTER; ioa_cfg->in_reset_reload = 0; @@ -7048,12 +7127,16 @@ static int ipr_ioa_reset_done(struct ipr_cmnd *ipr_cmd) } schedule_work(&ioa_cfg->work_q); - list_for_each_entry_safe(hostrcb, temp, &ioa_cfg->hostrcb_free_q, queue) { - list_del(&hostrcb->queue); - if (i++ < IPR_NUM_LOG_HCAMS) - ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_LOG_DATA, hostrcb); + for (j = 0; j < IPR_NUM_HCAMS; j++) { + list_del_init(&ioa_cfg->hostrcb[j]->queue); + if (j < IPR_NUM_LOG_HCAMS) + ipr_send_hcam(ioa_cfg, + IPR_HCAM_CDB_OP_CODE_LOG_DATA, + ioa_cfg->hostrcb[j]); else - ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE, hostrcb); + ipr_send_hcam(ioa_cfg, + IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE, + ioa_cfg->hostrcb[j]); } scsi_report_bus_reset(ioa_cfg->host, IPR_VSET_BUS); @@ -8335,7 +8418,7 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg) hostrcb = list_entry(ioa_cfg->hostrcb_free_q.next, struct ipr_hostrcb, queue); - list_del(&hostrcb->queue); + list_del_init(&hostrcb->queue); memset(&hostrcb->hcam, 0, sizeof(hostrcb->hcam)); rc = ipr_get_ldump_data_section(ioa_cfg, @@ -9332,7 +9415,7 @@ static void ipr_free_mem(struct ipr_ioa_cfg *ioa_cfg) dma_free_coherent(&ioa_cfg->pdev->dev, ioa_cfg->cfg_table_size, ioa_cfg->u.cfg_table, ioa_cfg->cfg_table_dma); - for (i = 0; i < IPR_NUM_HCAMS; i++) { + for (i = 0; i < IPR_MAX_HCAMS; i++) { dma_free_coherent(&ioa_cfg->pdev->dev, sizeof(struct ipr_hostrcb), ioa_cfg->hostrcb[i], @@ -9572,7 +9655,7 @@ static int ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg) if (!ioa_cfg->u.cfg_table) goto out_free_host_rrq; - for (i = 0; i < IPR_NUM_HCAMS; i++) { + for (i = 0; i < IPR_MAX_HCAMS; i++) { ioa_cfg->hostrcb[i] = dma_alloc_coherent(&pdev->dev, sizeof(struct ipr_hostrcb), &ioa_cfg->hostrcb_dma[i], @@ -9714,6 +9797,7 @@ static void ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg, INIT_LIST_HEAD(&ioa_cfg->hostrcb_free_q); INIT_LIST_HEAD(&ioa_cfg->hostrcb_pending_q); + INIT_LIST_HEAD(&ioa_cfg->hostrcb_report_q); INIT_LIST_HEAD(&ioa_cfg->free_res_q); INIT_LIST_HEAD(&ioa_cfg->used_res_q); INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread); @@ -10352,6 +10436,8 @@ static void ipr_remove(struct pci_dev *pdev) &ipr_trace_attr); ipr_remove_dump_file(&ioa_cfg->host->shost_dev.kobj, &ipr_dump_attr); + sysfs_remove_bin_file(&ioa_cfg->host->shost_dev.kobj, + &ipr_ioa_async_err_log); scsi_remove_host(ioa_cfg->host); __ipr_remove(pdev); @@ -10400,10 +10486,25 @@ static int ipr_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) return rc; } + rc = sysfs_create_bin_file(&ioa_cfg->host->shost_dev.kobj, + &ipr_ioa_async_err_log); + + if (rc) { + ipr_remove_dump_file(&ioa_cfg->host->shost_dev.kobj, + &ipr_dump_attr); + ipr_remove_trace_file(&ioa_cfg->host->shost_dev.kobj, + &ipr_trace_attr); + scsi_remove_host(ioa_cfg->host); + __ipr_remove(pdev); + return rc; + } + rc = ipr_create_dump_file(&ioa_cfg->host->shost_dev.kobj, &ipr_dump_attr); if (rc) { + sysfs_remove_bin_file(&ioa_cfg->host->shost_dev.kobj, + &ipr_ioa_async_err_log); ipr_remove_trace_file(&ioa_cfg->host->shost_dev.kobj, &ipr_trace_attr); scsi_remove_host(ioa_cfg->host); -- cgit v1.2.3 From 7b3871fd17a2092b21e44d614706bcb495389559 Mon Sep 17 00:00:00 2001 From: Brian King Date: Fri, 16 Sep 2016 16:51:36 -0500 Subject: scsi: ipr: Don't log unnecessary 9084 error details A 9084 error gets logged by the ipr adapter when adapter raw mode gets enabled. A bunch of unformatted hex data also gets logged for this error, which is of little use, so let's avoid logging it by default in order to avoid the log getting polluted with useless data. Signed-off-by: Brian King Reviewed-by: Gabriel Krisman Bertazi Signed-off-by: Martin K. Petersen --- drivers/scsi/ipr.c | 6 +++--- drivers/scsi/ipr.h | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/scsi/ipr.c') diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 5ecc32cecd10..762627c848bd 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -493,15 +493,15 @@ struct ipr_error_table_t ipr_error_table[] = { "9072: Link not operational transition"}, {0x066B8200, 0, IPR_DEFAULT_LOG_LEVEL, "9032: Array exposed but still protected"}, - {0x066B8300, 0, IPR_DEFAULT_LOG_LEVEL + 1, + {0x066B8300, 0, IPR_DEBUG_LOG_LEVEL, "70DD: Device forced failed by disrupt device command"}, {0x066B9100, 0, IPR_DEFAULT_LOG_LEVEL, "4061: Multipath redundancy level got better"}, {0x066B9200, 0, IPR_DEFAULT_LOG_LEVEL, "4060: Multipath redundancy level got worse"}, - {0x06808100, 0, IPR_DEFAULT_LOG_LEVEL, + {0x06808100, 0, IPR_DEBUG_LOG_LEVEL, "9083: Device raw mode enabled"}, - {0x06808200, 0, IPR_DEFAULT_LOG_LEVEL, + {0x06808200, 0, IPR_DEBUG_LOG_LEVEL, "9084: Device raw mode disabled"}, {0x07270000, 0, 0, "Failure due to other device"}, diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index 4dbeaafa0ba2..8995053d01b3 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -1506,6 +1506,7 @@ struct ipr_ioa_cfg { u8 log_level; #define IPR_MAX_LOG_LEVEL 4 #define IPR_DEFAULT_LOG_LEVEL 2 +#define IPR_DEBUG_LOG_LEVEL 3 #define IPR_NUM_TRACE_INDEX_BITS 8 #define IPR_NUM_TRACE_ENTRIES (1 << IPR_NUM_TRACE_INDEX_BITS) -- cgit v1.2.3 From 87adbe08b644cd4dfa078ec1a09be7d2b24ce97d Mon Sep 17 00:00:00 2001 From: Brian King Date: Fri, 16 Sep 2016 16:51:37 -0500 Subject: scsi: ipr: Remove redundant messages at adapter init time Whenever multiple HRRQs are enabled, which is the default setting now, we end up seeing the following message logged prior to initialization of each HRRQ: Starting IOA initialization sequence This results in 16 of these messages on most adapters, which serves little purpose. Change to just log this once. Signed-off-by: Brian King Reviewed-by: Gabriel Krisman Bertazi Signed-off-by: Martin K. Petersen --- drivers/scsi/ipr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/scsi/ipr.c') diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 762627c848bd..1b21c6331c56 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -8049,7 +8049,8 @@ static int ipr_ioafp_identify_hrrq(struct ipr_cmnd *ipr_cmd) ENTER; ipr_cmd->job_step = ipr_ioafp_std_inquiry; - dev_info(&ioa_cfg->pdev->dev, "Starting IOA initialization sequence.\n"); + if (ioa_cfg->identify_hrrq_index == 0) + dev_info(&ioa_cfg->pdev->dev, "Starting IOA initialization sequence.\n"); if (ioa_cfg->identify_hrrq_index < ioa_cfg->hrrq_num) { hrrq = &ioa_cfg->hrrq[ioa_cfg->identify_hrrq_index]; -- cgit v1.2.3 From 8a4236a2c7868768943a24dc7b1e2ff495836880 Mon Sep 17 00:00:00 2001 From: Brian King Date: Thu, 13 Oct 2016 14:45:24 -0500 Subject: scsi: ipr: Fix async error WARN_ON Commit afc3f83cb4a5 ("scsi: ipr: Add asynchronous error notification") introduced the warn on shown below. To fix this, rather than attempting to send the KOBJ_CHANGE uevent from interrupt context, which is what is causing the WARN_ON, just wake the ipr worker thread which will send a KOBJ_CHANGE uevent. [ 142.278120] WARNING: CPU: 15 PID: 0 at kernel/softirq.c:161 __local_bh_enable_ip+0x7c/0xd0 [ 142.278124] Modules linked in: ip6t_rpfilter ip6t_REJECT nf_reject_ipv6 ipt_REJECT nf_reject_ipv4 xt_conntrack ebtable_nat ebtable_broute bridge stp llc ebtable_filter ebtables ip6table_nat nf_conntrack_ipv6 nf_defrag_ipv6 nf_nat_ipv6 ip6table_mangle ip6table_security ip6table_raw ip6table_filter ip6_tables iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack iptable_mangle iptable_security iptable_raw iptable_filter ses enclosure scsi_transport_sas sg pseries_rng nfsd auth_rpcgss nfs_acl lockd grace sunrpc ip_tables xfs libcrc32c sr_mod sd_mod cdrom ipr libata ibmvscsi scsi_transport_srp ibmveth dm_mirror dm_region_hash dm_log dm_mod [ 142.278208] CPU: 15 PID: 0 Comm: swapper/15 Not tainted 4.8.0.ipr+ #21 [ 142.278213] task: c00000010cf24480 task.stack: c00000010cfec000 [ 142.278217] NIP: c0000000000c0c7c LR: c000000000881778 CTR: c0000000003c5bf0 [ 142.278221] REGS: c00000010cfef080 TRAP: 0700 Not tainted (4.8.0.ipr+) [ 142.278224] MSR: 8000000000029033 CR: 28008022 XER: 2000000f [ 142.278236] CFAR: c0000000000c0c20 SOFTE: 0 GPR00: c000000000706c78 c00000010cfef300 c000000000f91d00 c000000000706c78 GPR04: 0000000000000200 c000000000f7bc80 0000000000000000 00000000024000c0 GPR08: 0000000000000000 0000000000000001 c000000000ee1d00 c000000000a9bdd0 GPR12: c0000000003c5bf0 c00000000eb22d00 c000000100ca3880 c00000020ed38400 GPR16: 0000000000000000 0000000000000000 c000000100940508 0000000000000000 GPR20: 0000000000000000 0000000000000000 0000000000000000 00000000024000c0 GPR24: c0000000004588e0 c00000010863bd00 c00000010863bd00 c0000000013773f8 GPR28: c000000000f7bc80 0000000000000000 ffffffffffffffff c000000000f7bcd8 [ 142.278290] NIP [c0000000000c0c7c] __local_bh_enable_ip+0x7c/0xd0 [ 142.278296] LR [c000000000881778] _raw_spin_unlock_bh+0x38/0x60 [ 142.278299] Call Trace: [ 142.278303] [c00000010cfef300] [c000000000f7bc80] init_net+0x0/0x1900 (unreliable) [ 142.278310] [c00000010cfef320] [c000000000706c78] peernet2id+0x58/0x80 [ 142.278316] [c00000010cfef370] [c00000000075caec] netlink_broadcast_filtered+0x30c/0x550 [ 142.278323] [c00000010cfef430] [c000000000459078] kobject_uevent_env+0x588/0x780 [ 142.278331] [c00000010cfef510] [d000000003163a6c] ipr_process_error+0x11c/0x240 [ipr] [ 142.278337] [c00000010cfef5c0] [d000000003152298] ipr_fail_all_ops+0x108/0x220 [ipr] [ 142.278343] [c00000010cfef670] [d0000000031643f8] ipr_reset_restore_cfg_space+0xa8/0x240 [ipr] [ 142.278350] [c00000010cfef6f0] [d000000003158a00] ipr_reset_ioa_job+0x80/0xe0 [ipr] [ 142.278356] [c00000010cfef720] [d000000003153f78] ipr_reset_timer_done+0xa8/0xe0 [ipr] [ 142.278363] [c00000010cfef770] [c000000000149c88] call_timer_fn+0x58/0x1c0 [ 142.278368] [c00000010cfef800] [c000000000149f60] expire_timers+0x140/0x200 [ 142.278373] [c00000010cfef870] [c00000000014a0e8] run_timer_softirq+0xc8/0x230 [ 142.278379] [c00000010cfef900] [c0000000000c0844] __do_softirq+0x164/0x3c0 [ 142.278384] [c00000010cfef9f0] [c0000000000c0f18] irq_exit+0x1a8/0x1c0 [ 142.278389] [c00000010cfefa20] [c000000000020b54] timer_interrupt+0xa4/0xe0 [ 142.278394] [c00000010cfefa50] [c000000000002414] decrementer_common+0x114/0x180 Signed-off-by: Brian King Signed-off-by: Martin K. Petersen --- drivers/scsi/ipr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/scsi/ipr.c') diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index a8762a3efeef..532474109624 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -2586,7 +2586,6 @@ static void ipr_process_error(struct ipr_cmnd *ipr_cmd) struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb; u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc); u32 fd_ioasc; - char *envp[] = { "ASYNC_ERR_LOG=1", NULL }; if (ioa_cfg->sis64) fd_ioasc = be32_to_cpu(hostrcb->hcam.u.error64.fd_ioasc); @@ -2607,8 +2606,8 @@ static void ipr_process_error(struct ipr_cmnd *ipr_cmd) } list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_report_q); + schedule_work(&ioa_cfg->work_q); hostrcb = ipr_get_free_hostrcb(ioa_cfg); - kobject_uevent_env(&ioa_cfg->host->shost_dev.kobj, KOBJ_CHANGE, envp); ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_LOG_DATA, hostrcb); } -- cgit v1.2.3