aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian King <brking@linux.vnet.ibm.com>2016-08-24 13:56:51 -0400
committerMartin K. Petersen <martin.petersen@oracle.com>2016-08-25 23:39:15 -0400
commitafc3f83cb4a5bb3c8f18380bdeca6b65a6ff9543 (patch)
treed7fef8ffde79690a471775c0205d91d449bb3571
parent6328d9030f0fcf9935a00b1cd9d90c1129526a9c (diff)
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 <halves@linux.vnet.ibm.com> Signed-off-by: Gabriel Krisman Bertazi <krisman@linux.vnet.ibm.com> Signed-off-by: Brian King <brking@linux.vnet.ibm.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
-rw-r--r--drivers/scsi/ipr.c125
-rw-r--r--drivers/scsi/ipr.h7
2 files changed, 118 insertions, 14 deletions
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)
1473 struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb; 1473 struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb;
1474 u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc); 1474 u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc);
1475 1475
1476 list_del(&hostrcb->queue); 1476 list_del_init(&hostrcb->queue);
1477 list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); 1477 list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
1478 1478
1479 if (ioasc) { 1479 if (ioasc) {
@@ -2552,6 +2552,23 @@ static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg,
2552 } 2552 }
2553} 2553}
2554 2554
2555static struct ipr_hostrcb *ipr_get_free_hostrcb(struct ipr_ioa_cfg *ioa)
2556{
2557 struct ipr_hostrcb *hostrcb;
2558
2559 hostrcb = list_first_entry_or_null(&ioa->hostrcb_free_q,
2560 struct ipr_hostrcb, queue);
2561
2562 if (unlikely(!hostrcb)) {
2563 dev_info(&ioa->pdev->dev, "Reclaiming async error buffers.");
2564 hostrcb = list_first_entry_or_null(&ioa->hostrcb_report_q,
2565 struct ipr_hostrcb, queue);
2566 }
2567
2568 list_del_init(&hostrcb->queue);
2569 return hostrcb;
2570}
2571
2555/** 2572/**
2556 * ipr_process_error - Op done function for an adapter error log. 2573 * ipr_process_error - Op done function for an adapter error log.
2557 * @ipr_cmd: ipr command struct 2574 * @ipr_cmd: ipr command struct
@@ -2569,13 +2586,14 @@ static void ipr_process_error(struct ipr_cmnd *ipr_cmd)
2569 struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb; 2586 struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb;
2570 u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc); 2587 u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc);
2571 u32 fd_ioasc; 2588 u32 fd_ioasc;
2589 char *envp[] = { "ASYNC_ERR_LOG=1", NULL };
2572 2590
2573 if (ioa_cfg->sis64) 2591 if (ioa_cfg->sis64)
2574 fd_ioasc = be32_to_cpu(hostrcb->hcam.u.error64.fd_ioasc); 2592 fd_ioasc = be32_to_cpu(hostrcb->hcam.u.error64.fd_ioasc);
2575 else 2593 else
2576 fd_ioasc = be32_to_cpu(hostrcb->hcam.u.error.fd_ioasc); 2594 fd_ioasc = be32_to_cpu(hostrcb->hcam.u.error.fd_ioasc);
2577 2595
2578 list_del(&hostrcb->queue); 2596 list_del_init(&hostrcb->queue);
2579 list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); 2597 list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
2580 2598
2581 if (!ioasc) { 2599 if (!ioasc) {
@@ -2588,6 +2606,10 @@ static void ipr_process_error(struct ipr_cmnd *ipr_cmd)
2588 "Host RCB failed with IOASC: 0x%08X\n", ioasc); 2606 "Host RCB failed with IOASC: 0x%08X\n", ioasc);
2589 } 2607 }
2590 2608
2609 list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_report_q);
2610 hostrcb = ipr_get_free_hostrcb(ioa_cfg);
2611 kobject_uevent_env(&ioa_cfg->host->shost_dev.kobj, KOBJ_CHANGE, envp);
2612
2591 ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_LOG_DATA, hostrcb); 2613 ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_LOG_DATA, hostrcb);
2592} 2614}
2593 2615
@@ -4095,6 +4117,64 @@ static struct device_attribute ipr_ioa_fw_type_attr = {
4095 .show = ipr_show_fw_type 4117 .show = ipr_show_fw_type
4096}; 4118};
4097 4119
4120static ssize_t ipr_read_async_err_log(struct file *filep, struct kobject *kobj,
4121 struct bin_attribute *bin_attr, char *buf,
4122 loff_t off, size_t count)
4123{
4124 struct device *cdev = container_of(kobj, struct device, kobj);
4125 struct Scsi_Host *shost = class_to_shost(cdev);
4126 struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;
4127 struct ipr_hostrcb *hostrcb;
4128 unsigned long lock_flags = 0;
4129 int ret;
4130
4131 spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
4132 hostrcb = list_first_entry_or_null(&ioa_cfg->hostrcb_report_q,
4133 struct ipr_hostrcb, queue);
4134 if (!hostrcb) {
4135 spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
4136 return 0;
4137 }
4138 ret = memory_read_from_buffer(buf, count, &off, &hostrcb->hcam,
4139 sizeof(hostrcb->hcam));
4140 spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
4141 return ret;
4142}
4143
4144static ssize_t ipr_next_async_err_log(struct file *filep, struct kobject *kobj,
4145 struct bin_attribute *bin_attr, char *buf,
4146 loff_t off, size_t count)
4147{
4148 struct device *cdev = container_of(kobj, struct device, kobj);
4149 struct Scsi_Host *shost = class_to_shost(cdev);
4150 struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;
4151 struct ipr_hostrcb *hostrcb;
4152 unsigned long lock_flags = 0;
4153
4154 spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
4155 hostrcb = list_first_entry_or_null(&ioa_cfg->hostrcb_report_q,
4156 struct ipr_hostrcb, queue);
4157 if (!hostrcb) {
4158 spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
4159 return count;
4160 }
4161
4162 /* Reclaim hostrcb before exit */
4163 list_move_tail(&hostrcb->queue, &ioa_cfg->hostrcb_free_q);
4164 spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
4165 return count;
4166}
4167
4168static struct bin_attribute ipr_ioa_async_err_log = {
4169 .attr = {
4170 .name = "async_err_log",
4171 .mode = S_IRUGO | S_IWUSR,
4172 },
4173 .size = 0,
4174 .read = ipr_read_async_err_log,
4175 .write = ipr_next_async_err_log
4176};
4177
4098static struct device_attribute *ipr_ioa_attrs[] = { 4178static struct device_attribute *ipr_ioa_attrs[] = {
4099 &ipr_fw_version_attr, 4179 &ipr_fw_version_attr,
4100 &ipr_log_level_attr, 4180 &ipr_log_level_attr,
@@ -7026,8 +7106,7 @@ static int ipr_ioa_reset_done(struct ipr_cmnd *ipr_cmd)
7026{ 7106{
7027 struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 7107 struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
7028 struct ipr_resource_entry *res; 7108 struct ipr_resource_entry *res;
7029 struct ipr_hostrcb *hostrcb, *temp; 7109 int j;
7030 int i = 0, j;
7031 7110
7032 ENTER; 7111 ENTER;
7033 ioa_cfg->in_reset_reload = 0; 7112 ioa_cfg->in_reset_reload = 0;
@@ -7048,12 +7127,16 @@ static int ipr_ioa_reset_done(struct ipr_cmnd *ipr_cmd)
7048 } 7127 }
7049 schedule_work(&ioa_cfg->work_q); 7128 schedule_work(&ioa_cfg->work_q);
7050 7129
7051 list_for_each_entry_safe(hostrcb, temp, &ioa_cfg->hostrcb_free_q, queue) { 7130 for (j = 0; j < IPR_NUM_HCAMS; j++) {
7052 list_del(&hostrcb->queue); 7131 list_del_init(&ioa_cfg->hostrcb[j]->queue);
7053 if (i++ < IPR_NUM_LOG_HCAMS) 7132 if (j < IPR_NUM_LOG_HCAMS)
7054 ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_LOG_DATA, hostrcb); 7133 ipr_send_hcam(ioa_cfg,
7134 IPR_HCAM_CDB_OP_CODE_LOG_DATA,
7135 ioa_cfg->hostrcb[j]);
7055 else 7136 else
7056 ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE, hostrcb); 7137 ipr_send_hcam(ioa_cfg,
7138 IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE,
7139 ioa_cfg->hostrcb[j]);
7057 } 7140 }
7058 7141
7059 scsi_report_bus_reset(ioa_cfg->host, IPR_VSET_BUS); 7142 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)
8335 8418
8336 hostrcb = list_entry(ioa_cfg->hostrcb_free_q.next, 8419 hostrcb = list_entry(ioa_cfg->hostrcb_free_q.next,
8337 struct ipr_hostrcb, queue); 8420 struct ipr_hostrcb, queue);
8338 list_del(&hostrcb->queue); 8421 list_del_init(&hostrcb->queue);
8339 memset(&hostrcb->hcam, 0, sizeof(hostrcb->hcam)); 8422 memset(&hostrcb->hcam, 0, sizeof(hostrcb->hcam));
8340 8423
8341 rc = ipr_get_ldump_data_section(ioa_cfg, 8424 rc = ipr_get_ldump_data_section(ioa_cfg,
@@ -9332,7 +9415,7 @@ static void ipr_free_mem(struct ipr_ioa_cfg *ioa_cfg)
9332 dma_free_coherent(&ioa_cfg->pdev->dev, ioa_cfg->cfg_table_size, 9415 dma_free_coherent(&ioa_cfg->pdev->dev, ioa_cfg->cfg_table_size,
9333 ioa_cfg->u.cfg_table, ioa_cfg->cfg_table_dma); 9416 ioa_cfg->u.cfg_table, ioa_cfg->cfg_table_dma);
9334 9417
9335 for (i = 0; i < IPR_NUM_HCAMS; i++) { 9418 for (i = 0; i < IPR_MAX_HCAMS; i++) {
9336 dma_free_coherent(&ioa_cfg->pdev->dev, 9419 dma_free_coherent(&ioa_cfg->pdev->dev,
9337 sizeof(struct ipr_hostrcb), 9420 sizeof(struct ipr_hostrcb),
9338 ioa_cfg->hostrcb[i], 9421 ioa_cfg->hostrcb[i],
@@ -9572,7 +9655,7 @@ static int ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg)
9572 if (!ioa_cfg->u.cfg_table) 9655 if (!ioa_cfg->u.cfg_table)
9573 goto out_free_host_rrq; 9656 goto out_free_host_rrq;
9574 9657
9575 for (i = 0; i < IPR_NUM_HCAMS; i++) { 9658 for (i = 0; i < IPR_MAX_HCAMS; i++) {
9576 ioa_cfg->hostrcb[i] = dma_alloc_coherent(&pdev->dev, 9659 ioa_cfg->hostrcb[i] = dma_alloc_coherent(&pdev->dev,
9577 sizeof(struct ipr_hostrcb), 9660 sizeof(struct ipr_hostrcb),
9578 &ioa_cfg->hostrcb_dma[i], 9661 &ioa_cfg->hostrcb_dma[i],
@@ -9714,6 +9797,7 @@ static void ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
9714 9797
9715 INIT_LIST_HEAD(&ioa_cfg->hostrcb_free_q); 9798 INIT_LIST_HEAD(&ioa_cfg->hostrcb_free_q);
9716 INIT_LIST_HEAD(&ioa_cfg->hostrcb_pending_q); 9799 INIT_LIST_HEAD(&ioa_cfg->hostrcb_pending_q);
9800 INIT_LIST_HEAD(&ioa_cfg->hostrcb_report_q);
9717 INIT_LIST_HEAD(&ioa_cfg->free_res_q); 9801 INIT_LIST_HEAD(&ioa_cfg->free_res_q);
9718 INIT_LIST_HEAD(&ioa_cfg->used_res_q); 9802 INIT_LIST_HEAD(&ioa_cfg->used_res_q);
9719 INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread); 9803 INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread);
@@ -10352,6 +10436,8 @@ static void ipr_remove(struct pci_dev *pdev)
10352 &ipr_trace_attr); 10436 &ipr_trace_attr);
10353 ipr_remove_dump_file(&ioa_cfg->host->shost_dev.kobj, 10437 ipr_remove_dump_file(&ioa_cfg->host->shost_dev.kobj,
10354 &ipr_dump_attr); 10438 &ipr_dump_attr);
10439 sysfs_remove_bin_file(&ioa_cfg->host->shost_dev.kobj,
10440 &ipr_ioa_async_err_log);
10355 scsi_remove_host(ioa_cfg->host); 10441 scsi_remove_host(ioa_cfg->host);
10356 10442
10357 __ipr_remove(pdev); 10443 __ipr_remove(pdev);
@@ -10400,10 +10486,25 @@ static int ipr_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
10400 return rc; 10486 return rc;
10401 } 10487 }
10402 10488
10489 rc = sysfs_create_bin_file(&ioa_cfg->host->shost_dev.kobj,
10490 &ipr_ioa_async_err_log);
10491
10492 if (rc) {
10493 ipr_remove_dump_file(&ioa_cfg->host->shost_dev.kobj,
10494 &ipr_dump_attr);
10495 ipr_remove_trace_file(&ioa_cfg->host->shost_dev.kobj,
10496 &ipr_trace_attr);
10497 scsi_remove_host(ioa_cfg->host);
10498 __ipr_remove(pdev);
10499 return rc;
10500 }
10501
10403 rc = ipr_create_dump_file(&ioa_cfg->host->shost_dev.kobj, 10502 rc = ipr_create_dump_file(&ioa_cfg->host->shost_dev.kobj,
10404 &ipr_dump_attr); 10503 &ipr_dump_attr);
10405 10504
10406 if (rc) { 10505 if (rc) {
10506 sysfs_remove_bin_file(&ioa_cfg->host->shost_dev.kobj,
10507 &ipr_ioa_async_err_log);
10407 ipr_remove_trace_file(&ioa_cfg->host->shost_dev.kobj, 10508 ipr_remove_trace_file(&ioa_cfg->host->shost_dev.kobj,
10408 &ipr_trace_attr); 10509 &ipr_trace_attr);
10409 scsi_remove_host(ioa_cfg->host); 10510 scsi_remove_host(ioa_cfg->host);
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index cdb51960b53c..4dbeaafa0ba2 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -154,7 +154,9 @@
154#define IPR_DEFAULT_MAX_ERROR_DUMP 984 154#define IPR_DEFAULT_MAX_ERROR_DUMP 984
155#define IPR_NUM_LOG_HCAMS 2 155#define IPR_NUM_LOG_HCAMS 2
156#define IPR_NUM_CFG_CHG_HCAMS 2 156#define IPR_NUM_CFG_CHG_HCAMS 2
157#define IPR_NUM_HCAM_QUEUE 12
157#define IPR_NUM_HCAMS (IPR_NUM_LOG_HCAMS + IPR_NUM_CFG_CHG_HCAMS) 158#define IPR_NUM_HCAMS (IPR_NUM_LOG_HCAMS + IPR_NUM_CFG_CHG_HCAMS)
159#define IPR_MAX_HCAMS (IPR_NUM_HCAMS + IPR_NUM_HCAM_QUEUE)
158 160
159#define IPR_MAX_SIS64_TARGETS_PER_BUS 1024 161#define IPR_MAX_SIS64_TARGETS_PER_BUS 1024
160#define IPR_MAX_SIS64_LUNS_PER_TARGET 0xffffffff 162#define IPR_MAX_SIS64_LUNS_PER_TARGET 0xffffffff
@@ -1532,10 +1534,11 @@ struct ipr_ioa_cfg {
1532 1534
1533 char ipr_hcam_label[8]; 1535 char ipr_hcam_label[8];
1534#define IPR_HCAM_LABEL "hcams" 1536#define IPR_HCAM_LABEL "hcams"
1535 struct ipr_hostrcb *hostrcb[IPR_NUM_HCAMS]; 1537 struct ipr_hostrcb *hostrcb[IPR_MAX_HCAMS];
1536 dma_addr_t hostrcb_dma[IPR_NUM_HCAMS]; 1538 dma_addr_t hostrcb_dma[IPR_MAX_HCAMS];
1537 struct list_head hostrcb_free_q; 1539 struct list_head hostrcb_free_q;
1538 struct list_head hostrcb_pending_q; 1540 struct list_head hostrcb_pending_q;
1541 struct list_head hostrcb_report_q;
1539 1542
1540 struct ipr_hrr_queue hrrq[IPR_MAX_HRRQ_NUM]; 1543 struct ipr_hrr_queue hrrq[IPR_MAX_HRRQ_NUM];
1541 u32 hrrq_num; 1544 u32 hrrq_num;