Skip to content

Commit afc3f83

Browse files
bjking1martinkpetersen
authored andcommitted
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 <[email protected]> Signed-off-by: Gabriel Krisman Bertazi <[email protected]> Signed-off-by: Brian King <[email protected]> Signed-off-by: Martin K. Petersen <[email protected]>
1 parent 6328d90 commit afc3f83

File tree

2 files changed

+118
-14
lines changed

2 files changed

+118
-14
lines changed

drivers/scsi/ipr.c

+113-12
Original file line numberDiff line numberDiff line change
@@ -1473,7 +1473,7 @@ static void ipr_process_ccn(struct ipr_cmnd *ipr_cmd)
14731473
struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb;
14741474
u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc);
14751475

1476-
list_del(&hostrcb->queue);
1476+
list_del_init(&hostrcb->queue);
14771477
list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
14781478

14791479
if (ioasc) {
@@ -2552,6 +2552,23 @@ static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg,
25522552
}
25532553
}
25542554

2555+
static 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+
25552572
/**
25562573
* ipr_process_error - Op done function for an adapter error log.
25572574
* @ipr_cmd: ipr command struct
@@ -2569,13 +2586,14 @@ static void ipr_process_error(struct ipr_cmnd *ipr_cmd)
25692586
struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb;
25702587
u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc);
25712588
u32 fd_ioasc;
2589+
char *envp[] = { "ASYNC_ERR_LOG=1", NULL };
25722590

25732591
if (ioa_cfg->sis64)
25742592
fd_ioasc = be32_to_cpu(hostrcb->hcam.u.error64.fd_ioasc);
25752593
else
25762594
fd_ioasc = be32_to_cpu(hostrcb->hcam.u.error.fd_ioasc);
25772595

2578-
list_del(&hostrcb->queue);
2596+
list_del_init(&hostrcb->queue);
25792597
list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
25802598

25812599
if (!ioasc) {
@@ -2588,6 +2606,10 @@ static void ipr_process_error(struct ipr_cmnd *ipr_cmd)
25882606
"Host RCB failed with IOASC: 0x%08X\n", ioasc);
25892607
}
25902608

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+
25912613
ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_LOG_DATA, hostrcb);
25922614
}
25932615

@@ -4095,6 +4117,64 @@ static struct device_attribute ipr_ioa_fw_type_attr = {
40954117
.show = ipr_show_fw_type
40964118
};
40974119

4120+
static 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+
4144+
static 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+
4168+
static 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+
40984178
static struct device_attribute *ipr_ioa_attrs[] = {
40994179
&ipr_fw_version_attr,
41004180
&ipr_log_level_attr,
@@ -7026,8 +7106,7 @@ static int ipr_ioa_reset_done(struct ipr_cmnd *ipr_cmd)
70267106
{
70277107
struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
70287108
struct ipr_resource_entry *res;
7029-
struct ipr_hostrcb *hostrcb, *temp;
7030-
int i = 0, j;
7109+
int j;
70317110

70327111
ENTER;
70337112
ioa_cfg->in_reset_reload = 0;
@@ -7048,12 +7127,16 @@ static int ipr_ioa_reset_done(struct ipr_cmnd *ipr_cmd)
70487127
}
70497128
schedule_work(&ioa_cfg->work_q);
70507129

7051-
list_for_each_entry_safe(hostrcb, temp, &ioa_cfg->hostrcb_free_q, queue) {
7052-
list_del(&hostrcb->queue);
7053-
if (i++ < IPR_NUM_LOG_HCAMS)
7054-
ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_LOG_DATA, hostrcb);
7130+
for (j = 0; j < IPR_NUM_HCAMS; j++) {
7131+
list_del_init(&ioa_cfg->hostrcb[j]->queue);
7132+
if (j < IPR_NUM_LOG_HCAMS)
7133+
ipr_send_hcam(ioa_cfg,
7134+
IPR_HCAM_CDB_OP_CODE_LOG_DATA,
7135+
ioa_cfg->hostrcb[j]);
70557136
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]);
70577140
}
70587141

70597142
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)
83358418

83368419
hostrcb = list_entry(ioa_cfg->hostrcb_free_q.next,
83378420
struct ipr_hostrcb, queue);
8338-
list_del(&hostrcb->queue);
8421+
list_del_init(&hostrcb->queue);
83398422
memset(&hostrcb->hcam, 0, sizeof(hostrcb->hcam));
83408423

83418424
rc = ipr_get_ldump_data_section(ioa_cfg,
@@ -9332,7 +9415,7 @@ static void ipr_free_mem(struct ipr_ioa_cfg *ioa_cfg)
93329415
dma_free_coherent(&ioa_cfg->pdev->dev, ioa_cfg->cfg_table_size,
93339416
ioa_cfg->u.cfg_table, ioa_cfg->cfg_table_dma);
93349417

9335-
for (i = 0; i < IPR_NUM_HCAMS; i++) {
9418+
for (i = 0; i < IPR_MAX_HCAMS; i++) {
93369419
dma_free_coherent(&ioa_cfg->pdev->dev,
93379420
sizeof(struct ipr_hostrcb),
93389421
ioa_cfg->hostrcb[i],
@@ -9572,7 +9655,7 @@ static int ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg)
95729655
if (!ioa_cfg->u.cfg_table)
95739656
goto out_free_host_rrq;
95749657

9575-
for (i = 0; i < IPR_NUM_HCAMS; i++) {
9658+
for (i = 0; i < IPR_MAX_HCAMS; i++) {
95769659
ioa_cfg->hostrcb[i] = dma_alloc_coherent(&pdev->dev,
95779660
sizeof(struct ipr_hostrcb),
95789661
&ioa_cfg->hostrcb_dma[i],
@@ -9714,6 +9797,7 @@ static void ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
97149797

97159798
INIT_LIST_HEAD(&ioa_cfg->hostrcb_free_q);
97169799
INIT_LIST_HEAD(&ioa_cfg->hostrcb_pending_q);
9800+
INIT_LIST_HEAD(&ioa_cfg->hostrcb_report_q);
97179801
INIT_LIST_HEAD(&ioa_cfg->free_res_q);
97189802
INIT_LIST_HEAD(&ioa_cfg->used_res_q);
97199803
INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread);
@@ -10352,6 +10436,8 @@ static void ipr_remove(struct pci_dev *pdev)
1035210436
&ipr_trace_attr);
1035310437
ipr_remove_dump_file(&ioa_cfg->host->shost_dev.kobj,
1035410438
&ipr_dump_attr);
10439+
sysfs_remove_bin_file(&ioa_cfg->host->shost_dev.kobj,
10440+
&ipr_ioa_async_err_log);
1035510441
scsi_remove_host(ioa_cfg->host);
1035610442

1035710443
__ipr_remove(pdev);
@@ -10400,10 +10486,25 @@ static int ipr_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
1040010486
return rc;
1040110487
}
1040210488

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+
1040310502
rc = ipr_create_dump_file(&ioa_cfg->host->shost_dev.kobj,
1040410503
&ipr_dump_attr);
1040510504

1040610505
if (rc) {
10506+
sysfs_remove_bin_file(&ioa_cfg->host->shost_dev.kobj,
10507+
&ipr_ioa_async_err_log);
1040710508
ipr_remove_trace_file(&ioa_cfg->host->shost_dev.kobj,
1040810509
&ipr_trace_attr);
1040910510
scsi_remove_host(ioa_cfg->host);

drivers/scsi/ipr.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,9 @@
154154
#define IPR_DEFAULT_MAX_ERROR_DUMP 984
155155
#define IPR_NUM_LOG_HCAMS 2
156156
#define IPR_NUM_CFG_CHG_HCAMS 2
157+
#define IPR_NUM_HCAM_QUEUE 12
157158
#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)
158160

159161
#define IPR_MAX_SIS64_TARGETS_PER_BUS 1024
160162
#define IPR_MAX_SIS64_LUNS_PER_TARGET 0xffffffff
@@ -1532,10 +1534,11 @@ struct ipr_ioa_cfg {
15321534

15331535
char ipr_hcam_label[8];
15341536
#define IPR_HCAM_LABEL "hcams"
1535-
struct ipr_hostrcb *hostrcb[IPR_NUM_HCAMS];
1536-
dma_addr_t hostrcb_dma[IPR_NUM_HCAMS];
1537+
struct ipr_hostrcb *hostrcb[IPR_MAX_HCAMS];
1538+
dma_addr_t hostrcb_dma[IPR_MAX_HCAMS];
15371539
struct list_head hostrcb_free_q;
15381540
struct list_head hostrcb_pending_q;
1541+
struct list_head hostrcb_report_q;
15391542

15401543
struct ipr_hrr_queue hrrq[IPR_MAX_HRRQ_NUM];
15411544
u32 hrrq_num;

0 commit comments

Comments
 (0)