From 5adcbeb34d2a031d3baca227eef23e56734006ba Mon Sep 17 00:00:00 2001 From: Wayne Boyer Date: Thu, 3 Jun 2010 16:02:21 -0700 Subject: [SCSI] ipr: fix resource path display and formatting It was possible to overflow the buffer used to print out the formatted version of the resource path. The fix is to limit the number of bytes that get formatted. This patch also updates the ipr_show_resource_path function to display the resource address for devices that are attached to adapters that don't support resource paths. Signed-off-by: Wayne Boyer Acked-by: Brian King Signed-off-by: James Bottomley diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 82ea4a8..f820cff 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -1129,20 +1129,22 @@ static int ipr_is_same_device(struct ipr_resource_entry *res, } /** - * ipr_format_resource_path - Format the resource path for printing. + * ipr_format_res_path - Format the resource path for printing. * @res_path: resource path * @buf: buffer * * Return value: * pointer to buffer **/ -static char *ipr_format_resource_path(u8 *res_path, char *buffer) +static char *ipr_format_res_path(u8 *res_path, char *buffer, int len) { int i; + char *p = buffer; - sprintf(buffer, "%02X", res_path[0]); - for (i=1; res_path[i] != 0xff; i++) - sprintf(buffer, "%s-%02X", buffer, res_path[i]); + res_path[0] = '\0'; + p += snprintf(p, buffer + len - p, "%02X", res_path[0]); + for (i = 1; res_path[i] != 0xff && ((i * 3) < len); i++) + p += snprintf(p, buffer + len - p, "-%02X", res_path[i]); return buffer; } @@ -1187,7 +1189,8 @@ static void ipr_update_res_entry(struct ipr_resource_entry *res, if (res->sdev && new_path) sdev_printk(KERN_INFO, res->sdev, "Resource path: %s\n", - ipr_format_resource_path(&res->res_path[0], &buffer[0])); + ipr_format_res_path(res->res_path, buffer, + sizeof(buffer))); } else { res->flags = cfgtew->u.cfgte->flags; if (res->flags & IPR_IS_IOA_RESOURCE) @@ -1573,7 +1576,8 @@ static void ipr_log_sis64_config_error(struct ipr_ioa_cfg *ioa_cfg, ipr_err_separator; ipr_err("Device %d : %s", i + 1, - ipr_format_resource_path(&dev_entry->res_path[0], &buffer[0])); + ipr_format_res_path(dev_entry->res_path, buffer, + sizeof(buffer))); ipr_log_ext_vpd(&dev_entry->vpd); ipr_err("-----New Device Information-----\n"); @@ -1919,13 +1923,14 @@ static void ipr_log64_fabric_path(struct ipr_hostrcb *hostrcb, ipr_hcam_err(hostrcb, "%s %s: Resource Path=%s\n", path_active_desc[i].desc, path_state_desc[j].desc, - ipr_format_resource_path(&fabric->res_path[0], &buffer[0])); + ipr_format_res_path(fabric->res_path, buffer, + sizeof(buffer))); return; } } ipr_err("Path state=%02X Resource Path=%s\n", path_state, - ipr_format_resource_path(&fabric->res_path[0], &buffer[0])); + ipr_format_res_path(fabric->res_path, buffer, sizeof(buffer))); } static const struct { @@ -2066,7 +2071,8 @@ static void ipr_log64_path_elem(struct ipr_hostrcb *hostrcb, ipr_hcam_err(hostrcb, "%s %s: Resource Path=%s, Link rate=%s, WWN=%08X%08X\n", path_status_desc[j].desc, path_type_desc[i].desc, - ipr_format_resource_path(&cfg->res_path[0], &buffer[0]), + ipr_format_res_path(cfg->res_path, buffer, + sizeof(buffer)), link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); return; @@ -2074,7 +2080,7 @@ static void ipr_log64_path_elem(struct ipr_hostrcb *hostrcb, } ipr_hcam_err(hostrcb, "Path element=%02X: Resource Path=%s, Link rate=%s " "WWN=%08X%08X\n", cfg->type_status, - ipr_format_resource_path(&cfg->res_path[0], &buffer[0]), + ipr_format_res_path(cfg->res_path, buffer, sizeof(buffer)), link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); } @@ -2139,7 +2145,7 @@ static void ipr_log_sis64_array_error(struct ipr_ioa_cfg *ioa_cfg, ipr_err("RAID %s Array Configuration: %s\n", error->protection_level, - ipr_format_resource_path(&error->last_res_path[0], &buffer[0])); + ipr_format_res_path(error->last_res_path, buffer, sizeof(buffer))); ipr_err_separator; @@ -2160,9 +2166,11 @@ static void ipr_log_sis64_array_error(struct ipr_ioa_cfg *ioa_cfg, ipr_err("Array Member %d:\n", i); ipr_log_ext_vpd(&array_entry->vpd); ipr_err("Current Location: %s", - ipr_format_resource_path(&array_entry->res_path[0], &buffer[0])); + ipr_format_res_path(array_entry->res_path, buffer, + sizeof(buffer))); ipr_err("Expected Location: %s", - ipr_format_resource_path(&array_entry->expected_res_path[0], &buffer[0])); + ipr_format_res_path(array_entry->expected_res_path, + buffer, sizeof(buffer))); ipr_err_separator; } @@ -4079,7 +4087,8 @@ static struct device_attribute ipr_adapter_handle_attr = { }; /** - * ipr_show_resource_path - Show the resource path for this device. + * ipr_show_resource_path - Show the resource path or the resource address for + * this device. * @dev: device struct * @buf: buffer * @@ -4097,9 +4106,14 @@ static ssize_t ipr_show_resource_path(struct device *dev, struct device_attribut spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); res = (struct ipr_resource_entry *)sdev->hostdata; - if (res) + if (res && ioa_cfg->sis64) len = snprintf(buf, PAGE_SIZE, "%s\n", - ipr_format_resource_path(&res->res_path[0], &buffer[0])); + ipr_format_res_path(res->res_path, buffer, + sizeof(buffer))); + else if (res) + len = snprintf(buf, PAGE_SIZE, "%d:%d:%d:%d\n", ioa_cfg->host->host_no, + res->bus, res->target, res->lun); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); return len; } @@ -4351,7 +4365,8 @@ static int ipr_slave_configure(struct scsi_device *sdev) scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); if (ioa_cfg->sis64) sdev_printk(KERN_INFO, sdev, "Resource path: %s\n", - ipr_format_resource_path(&res->res_path[0], &buffer[0])); + ipr_format_res_path(res->res_path, buffer, + sizeof(buffer))); return 0; } spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index 9ecd225..b965f35 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -1684,8 +1684,9 @@ struct ipr_ucode_image_header { if (ipr_is_device(hostrcb)) { \ if ((hostrcb)->ioa_cfg->sis64) { \ printk(KERN_ERR IPR_NAME ": %s: " fmt, \ - ipr_format_resource_path(&hostrcb->hcam.u.error64.fd_res_path[0], \ - &hostrcb->rp_buffer[0]), \ + ipr_format_res_path(hostrcb->hcam.u.error64.fd_res_path, \ + hostrcb->rp_buffer, \ + sizeof(hostrcb->rp_buffer)), \ __VA_ARGS__); \ } else { \ ipr_ra_err((hostrcb)->ioa_cfg, \ -- cgit v0.10.2 From 30b6777b8931afc5f3aa42858fe917938b570f79 Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Mon, 21 Jun 2010 10:11:31 +0200 Subject: [SCSI] zfcp: Fix check whether unchained ct_els is possible A false check was performed whether an unchained ct_els is possible or not. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 9ac6a6e..4e15361 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -981,7 +981,7 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req, } /* use single, unchained SBAL if it can hold the request */ - if (zfcp_qdio_sg_one_sbale(sg_req) || zfcp_qdio_sg_one_sbale(sg_resp)) { + if (zfcp_qdio_sg_one_sbale(sg_req) && zfcp_qdio_sg_one_sbale(sg_resp)) { zfcp_fsf_setup_ct_els_unchained(adapter->qdio, &req->qdio_req, sg_req, sg_resp); return 0; -- cgit v0.10.2 From c2af7545aaff3495d9bf9a7608c52f0af86fb194 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Mon, 21 Jun 2010 10:11:32 +0200 Subject: [SCSI] zfcp: Do not wait for SBALs on stopped queue Trying to read the FC host statistics on an offline adapter results in a 5 seconds wait. Reading the statistics tries to issue an exchange port data request which first waits up to 5 seconds for an entry in the request queue. Change the strategy for getting a free SBAL to exit when the queue is stopped. Reading the statistics will then fail without the wait. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 4e15361..229795f 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -719,11 +719,6 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio, zfcp_qdio_req_init(adapter->qdio, &req->qdio_req, req->req_id, sbtype, req->qtcb, sizeof(struct fsf_qtcb)); - if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) { - zfcp_fsf_req_free(req); - return ERR_PTR(-EIO); - } - return req; } diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 28117e1..6fa5e04 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -251,7 +251,8 @@ static int zfcp_qdio_sbal_check(struct zfcp_qdio *qdio) struct zfcp_qdio_queue *req_q = &qdio->req_q; spin_lock_bh(&qdio->req_q_lock); - if (atomic_read(&req_q->count)) + if (atomic_read(&req_q->count) || + !(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) return 1; spin_unlock_bh(&qdio->req_q_lock); return 0; @@ -274,8 +275,13 @@ int zfcp_qdio_sbal_get(struct zfcp_qdio *qdio) spin_unlock_bh(&qdio->req_q_lock); ret = wait_event_interruptible_timeout(qdio->req_q_wq, zfcp_qdio_sbal_check(qdio), 5 * HZ); + + if (!(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) + return -EIO; + if (ret > 0) return 0; + if (!ret) { atomic_inc(&qdio->req_q_full); /* assume hanging outbound queue, try queue recovery */ @@ -375,6 +381,8 @@ void zfcp_qdio_close(struct zfcp_qdio *qdio) atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &qdio->adapter->status); spin_unlock_bh(&qdio->req_q_lock); + wake_up(&qdio->req_q_wq); + qdio_shutdown(qdio->adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR); -- cgit v0.10.2 From 8d88cf3f3b9af4713642caeb221b6d6a42019001 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Mon, 21 Jun 2010 10:11:33 +0200 Subject: [SCSI] zfcp: Update status read mempool Commit 64deb6efdc5504ce97b5c1c6f281fffbc150bd93 changed the way status read buffers are handled but forgot to adjust the mempool to the new size. Add the call to resize the mempool after the exchange config data. Also use the define instead of the hard coded number in the fsf callback for consistency. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index e3dbeda..fd068bc 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -714,6 +714,14 @@ static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *act) if (zfcp_erp_adapter_strategy_open_fsf_xport(act) == ZFCP_ERP_FAILED) return ZFCP_ERP_FAILED; + if (mempool_resize(act->adapter->pool.status_read_data, + act->adapter->stat_read_buf_num, GFP_KERNEL)) + return ZFCP_ERP_FAILED; + + if (mempool_resize(act->adapter->pool.status_read_req, + act->adapter->stat_read_buf_num, GFP_KERNEL)) + return ZFCP_ERP_FAILED; + atomic_set(&act->adapter->stat_miss, act->adapter->stat_read_buf_num); if (zfcp_status_read_refill(act->adapter)) return ZFCP_ERP_FAILED; diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 229795f..71663fb 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -496,7 +496,8 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req) adapter->hydra_version = bottom->adapter_type; adapter->timer_ticks = bottom->timer_interval; - adapter->stat_read_buf_num = max(bottom->status_read_buf_num, (u16)16); + adapter->stat_read_buf_num = max(bottom->status_read_buf_num, + (u16)FSF_STATUS_READS_RECOM); if (fc_host_permanent_port_name(shost) == -1) fc_host_permanent_port_name(shost) = fc_host_port_name(shost); -- cgit v0.10.2 From 8f83d7688026729c9d356d865f65a8996f090048 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Tue, 13 Jul 2010 14:59:29 +1000 Subject: [SCSI] ibmvscsi: Fix oops when an interrupt is pending during probe A driver needs to be ready to take an interrupt as soon as it registers an interrupt handler. I noticed the following oops when testing kdump: ipr: IBM Power RAID SCSI Device Driver version: 2.5.0 (February 11, 2010) ibmvscsi 30000002: SRP_VERSION: 16.a ibmvscsi 30000002: SRP_VERSION: 16.a Unable to handle kernel paging request for data at address 0x00000000 ... pc: c000000004085e34: .tasklet_action+0xf4/0x1dc ... c000000004086fe4 .__do_softirq+0x16c/0x2c0 c00000000403138c .call_do_softirq+0x14/0x24 c00000000400ee14 .do_softirq+0xa0/0x104 c00000000408690c .irq_exit+0x70/0xd0 c00000000400f190 .do_IRQ+0x214/0x2a8 c000000004004804 hardware_interrupt_entry+0x1c/0x98 --- Exception: 501 (Hardware Interrupt) at c00000000400c544 .raw_local_irq_restore+0x48/0x54 c00000000465d2a8 ._raw_spin_unlock_irqrestore+0x74/0xa0 c0000000040e7f00 .__setup_irq+0x2ec/0x3f0 c0000000040e8198 .request_threaded_irq+0x194/0x22c c00000000446d854 .rpavscsi_init_crq_queue+0x284/0x3f0 c00000000446c764 .ibmvscsi_probe+0x688/0x710 c00000000402903c .vio_bus_probe+0x37c/0x3e4 c000000004403f10 .driver_probe_device+0xec/0x1b8 c000000004404088 .__driver_attach+0xac/0xf4 c000000004403184 .bus_for_each_dev+0x98/0x104 c000000004403c98 .driver_attach+0x40/0x60 c0000000044026f0 .bus_add_driver+0x154/0x324 c0000000044045d0 .driver_register+0xe8/0x1ac c00000000402b2a8 .vio_register_driver+0x54/0x74 c000000004933ea4 .ibmvscsi_module_init+0x80/0xc0 c000000004009834 .do_one_initcall+0x98/0x1d8 c0000000049005b4 .kernel_init+0x27c/0x33c c000000004031550 .kernel_thread+0x54/0x70 srp_task needs to be setup before request_irq. The patch below fixes the oops. Signed-off-by: Anton Blanchard Acked-by: Brian King Signed-off-by: James Bottomley diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c index a864ccc..989b9a8 100644 --- a/drivers/scsi/ibmvscsi/rpa_vscsi.c +++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c @@ -277,6 +277,12 @@ static int rpavscsi_init_crq_queue(struct crq_queue *queue, goto reg_crq_failed; } + queue->cur = 0; + spin_lock_init(&queue->lock); + + tasklet_init(&hostdata->srp_task, (void *)rpavscsi_task, + (unsigned long)hostdata); + if (request_irq(vdev->irq, rpavscsi_handle_event, 0, "ibmvscsi", (void *)hostdata) != 0) { @@ -291,15 +297,10 @@ static int rpavscsi_init_crq_queue(struct crq_queue *queue, goto req_irq_failed; } - queue->cur = 0; - spin_lock_init(&queue->lock); - - tasklet_init(&hostdata->srp_task, (void *)rpavscsi_task, - (unsigned long)hostdata); - return retrc; req_irq_failed: + tasklet_kill(&hostdata->srp_task); do { rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc))); -- cgit v0.10.2