diff options
-rw-r--r-- | drivers/scsi/ipr.c | 125 | ||||
-rw-r--r-- | drivers/scsi/ipr.h | 7 |
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 | ||
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 | |||
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 | ||
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 | |||
4098 | static struct device_attribute *ipr_ioa_attrs[] = { | 4178 | static 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; |