diff options
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/kvm/kvm_virtio.c | 34 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_aux.c | 110 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_ccw.c | 6 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_cfdc.c | 17 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_dbf.c | 12 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_dbf.h | 1 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_def.h | 32 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_erp.c | 10 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fc.c | 88 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.c | 77 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.h | 2 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_qdio.c | 4 |
12 files changed, 184 insertions, 209 deletions
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c index 3d442444c618..28c90b89f2b4 100644 --- a/drivers/s390/kvm/kvm_virtio.c +++ b/drivers/s390/kvm/kvm_virtio.c @@ -188,11 +188,13 @@ static struct virtqueue *kvm_find_vq(struct virtio_device *vdev, config = kvm_vq_config(kdev->desc)+index; err = vmem_add_mapping(config->address, - vring_size(config->num, PAGE_SIZE)); + vring_size(config->num, + KVM_S390_VIRTIO_RING_ALIGN)); if (err) goto out; - vq = vring_new_virtqueue(config->num, vdev, (void *) config->address, + vq = vring_new_virtqueue(config->num, KVM_S390_VIRTIO_RING_ALIGN, + vdev, (void *) config->address, kvm_notify, callback); if (!vq) { err = -ENOMEM; @@ -209,7 +211,8 @@ static struct virtqueue *kvm_find_vq(struct virtio_device *vdev, return vq; unmap: vmem_remove_mapping(config->address, - vring_size(config->num, PAGE_SIZE)); + vring_size(config->num, + KVM_S390_VIRTIO_RING_ALIGN)); out: return ERR_PTR(err); } @@ -220,7 +223,8 @@ static void kvm_del_vq(struct virtqueue *vq) vring_del_virtqueue(vq); vmem_remove_mapping(config->address, - vring_size(config->num, PAGE_SIZE)); + vring_size(config->num, + KVM_S390_VIRTIO_RING_ALIGN)); } /* @@ -295,13 +299,29 @@ static void scan_devices(void) */ static void kvm_extint_handler(u16 code) { - void *data = (void *) *(long *) __LC_PFAULT_INTPARM; - u16 subcode = S390_lowcore.cpu_addr; + struct virtqueue *vq; + u16 subcode; + int config_changed; + subcode = S390_lowcore.cpu_addr; if ((subcode & 0xff00) != VIRTIO_SUBCODE_64) return; - vring_interrupt(0, data); + /* The LSB might be overloaded, we have to mask it */ + vq = (struct virtqueue *) ((*(long *) __LC_PFAULT_INTPARM) & ~1UL); + + /* We use the LSB of extparam, to decide, if this interrupt is a config + * change or a "standard" interrupt */ + config_changed = (*(int *) __LC_EXT_PARAMS & 1); + + if (config_changed) { + struct virtio_driver *drv; + drv = container_of(vq->vdev->dev.driver, + struct virtio_driver, driver); + if (drv->config_changed) + drv->config_changed(vq->vdev); + } else + vring_interrupt(0, vq); } /* diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index e529b55b3ce9..8af7dfbe022c 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -34,13 +34,12 @@ #define ZFCP_BUS_ID_SIZE 20 -static char *device; - MODULE_AUTHOR("IBM Deutschland Entwicklung GmbH - linux390@de.ibm.com"); MODULE_DESCRIPTION("FCP HBA driver"); MODULE_LICENSE("GPL"); -module_param(device, charp, 0400); +static char *init_device; +module_param_named(device, init_device, charp, 0400); MODULE_PARM_DESC(device, "specify initial device"); static int zfcp_reqlist_alloc(struct zfcp_adapter *adapter) @@ -73,46 +72,7 @@ int zfcp_reqlist_isempty(struct zfcp_adapter *adapter) return 1; } -static int __init zfcp_device_setup(char *devstr) -{ - char *token; - char *str; - - if (!devstr) - return 0; - - /* duplicate devstr and keep the original for sysfs presentation*/ - str = kmalloc(strlen(devstr) + 1, GFP_KERNEL); - if (!str) - return 0; - - strcpy(str, devstr); - - token = strsep(&str, ","); - if (!token || strlen(token) >= ZFCP_BUS_ID_SIZE) - goto err_out; - strncpy(zfcp_data.init_busid, token, ZFCP_BUS_ID_SIZE); - - token = strsep(&str, ","); - if (!token || strict_strtoull(token, 0, - (unsigned long long *) &zfcp_data.init_wwpn)) - goto err_out; - - token = strsep(&str, ","); - if (!token || strict_strtoull(token, 0, - (unsigned long long *) &zfcp_data.init_fcp_lun)) - goto err_out; - - kfree(str); - return 1; - - err_out: - kfree(str); - pr_err("%s is not a valid SCSI device\n", devstr); - return 0; -} - -static void __init zfcp_init_device_configure(void) +static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun) { struct zfcp_adapter *adapter; struct zfcp_port *port; @@ -120,17 +80,17 @@ static void __init zfcp_init_device_configure(void) down(&zfcp_data.config_sema); read_lock_irq(&zfcp_data.config_lock); - adapter = zfcp_get_adapter_by_busid(zfcp_data.init_busid); + adapter = zfcp_get_adapter_by_busid(busid); if (adapter) zfcp_adapter_get(adapter); read_unlock_irq(&zfcp_data.config_lock); if (!adapter) goto out_adapter; - port = zfcp_port_enqueue(adapter, zfcp_data.init_wwpn, 0, 0); + port = zfcp_port_enqueue(adapter, wwpn, 0, 0); if (IS_ERR(port)) goto out_port; - unit = zfcp_unit_enqueue(port, zfcp_data.init_fcp_lun); + unit = zfcp_unit_enqueue(port, lun); if (IS_ERR(unit)) goto out_unit; up(&zfcp_data.config_sema); @@ -160,6 +120,42 @@ static struct kmem_cache *zfcp_cache_create(int size, char *name) return kmem_cache_create(name , size, align, 0, NULL); } +static void __init zfcp_init_device_setup(char *devstr) +{ + char *token; + char *str; + char busid[ZFCP_BUS_ID_SIZE]; + u64 wwpn, lun; + + /* duplicate devstr and keep the original for sysfs presentation*/ + str = kmalloc(strlen(devstr) + 1, GFP_KERNEL); + if (!str) + return; + + strcpy(str, devstr); + + token = strsep(&str, ","); + if (!token || strlen(token) >= ZFCP_BUS_ID_SIZE) + goto err_out; + strncpy(busid, token, ZFCP_BUS_ID_SIZE); + + token = strsep(&str, ","); + if (!token || strict_strtoull(token, 0, (unsigned long long *) &wwpn)) + goto err_out; + + token = strsep(&str, ","); + if (!token || strict_strtoull(token, 0, (unsigned long long *) &lun)) + goto err_out; + + kfree(str); + zfcp_init_device_configure(busid, wwpn, lun); + return; + + err_out: + kfree(str); + pr_err("%s is not a valid SCSI device\n", devstr); +} + static int __init zfcp_module_init(void) { int retval = -ENOMEM; @@ -181,7 +177,6 @@ static int __init zfcp_module_init(void) zfcp_data.work_queue = create_singlethread_workqueue("zfcp_wq"); - INIT_LIST_HEAD(&zfcp_data.adapter_list_head); sema_init(&zfcp_data.config_sema, 1); rwlock_init(&zfcp_data.config_lock); @@ -203,10 +198,9 @@ static int __init zfcp_module_init(void) goto out_ccw_register; } - if (zfcp_device_setup(device)) - zfcp_init_device_configure(); - - goto out; + if (init_device) + zfcp_init_device_setup(init_device); + return 0; out_ccw_register: misc_deregister(&zfcp_cfdc_misc); @@ -527,14 +521,11 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) &zfcp_sysfs_adapter_attrs)) goto sysfs_failed; - write_lock_irq(&zfcp_data.config_lock); atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); - list_add_tail(&adapter->list, &zfcp_data.adapter_list_head); - write_unlock_irq(&zfcp_data.config_lock); - zfcp_fc_nameserver_init(adapter); - return 0; + if (!zfcp_adapter_scsi_register(adapter)) + return 0; sysfs_failed: zfcp_adapter_debug_unregister(adapter); @@ -573,14 +564,7 @@ void zfcp_adapter_dequeue(struct zfcp_adapter *adapter) return; zfcp_adapter_debug_unregister(adapter); - - /* remove specified adapter data structure from list */ - write_lock_irq(&zfcp_data.config_lock); - list_del(&adapter->list); - write_unlock_irq(&zfcp_data.config_lock); - zfcp_qdio_free(adapter); - zfcp_free_low_mem_buffers(adapter); kfree(adapter->req_list); kfree(adapter->fc_stats); diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index 728147131e1d..285881f07648 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -106,10 +106,6 @@ static int zfcp_ccw_set_online(struct ccw_device *ccw_device) if (retval) goto out; - retval = zfcp_adapter_scsi_register(adapter); - if (retval) - goto out_scsi_register; - /* initialize request counter */ BUG_ON(!zfcp_reqlist_isempty(adapter)); adapter->req_no = 0; @@ -123,8 +119,6 @@ static int zfcp_ccw_set_online(struct ccw_device *ccw_device) flush_work(&adapter->scan_work); return 0; - out_scsi_register: - zfcp_erp_thread_kill(adapter); out: up(&zfcp_data.config_sema); return retval; diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c index f1a7518e67ed..10cbfd172a28 100644 --- a/drivers/s390/scsi/zfcp_cfdc.c +++ b/drivers/s390/scsi/zfcp_cfdc.c @@ -85,20 +85,9 @@ static int zfcp_cfdc_copy_to_user(void __user *user_buffer, static struct zfcp_adapter *zfcp_cfdc_get_adapter(u32 devno) { - struct zfcp_adapter *adapter = NULL, *cur_adapter; - struct ccw_dev_id dev_id; - - read_lock_irq(&zfcp_data.config_lock); - list_for_each_entry(cur_adapter, &zfcp_data.adapter_list_head, list) { - ccw_device_get_id(cur_adapter->ccw_device, &dev_id); - if (dev_id.devno == devno) { - adapter = cur_adapter; - zfcp_adapter_get(adapter); - break; - } - } - read_unlock_irq(&zfcp_data.config_lock); - return adapter; + char busid[9]; + snprintf(busid, sizeof(busid), "0.0.%04x", devno); + return zfcp_get_adapter_by_busid(busid); } static int zfcp_cfdc_set_fsf(struct zfcp_fsf_cfdc *fsf_cfdc, int command) diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 735d675623f8..cb6df609953e 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -522,7 +522,7 @@ static const char *zfcp_rec_dbf_ids[] = { [29] = "link down", [30] = "link up status read", [31] = "open port failed", - [32] = "open port failed", + [32] = "", [33] = "close port", [34] = "open unit failed", [35] = "exclusive open unit failed", @@ -936,6 +936,7 @@ void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req) rct->reason_code = hdr->reason_code; rct->expl = hdr->reason_code_expl; rct->vendor_unique = hdr->vendor_unique; + rct->max_res_size = hdr->max_res_size; rct->len = min((int)ct->resp->length - (int)sizeof(struct ct_hdr), ZFCP_DBF_SAN_MAX_PAYLOAD); debug_event(adapter->san_dbf, level, r, sizeof(*r)); @@ -1043,6 +1044,7 @@ static int zfcp_san_dbf_view_format(debug_info_t *id, struct debug_view *view, zfcp_dbf_out(&p, "reason_code", "0x%02x", ct->reason_code); zfcp_dbf_out(&p, "reason_code_expl", "0x%02x", ct->expl); zfcp_dbf_out(&p, "vendor_unique", "0x%02x", ct->vendor_unique); + zfcp_dbf_out(&p, "max_res_size", "0x%04x", ct->max_res_size); } else if (strncmp(r->tag, "oels", ZFCP_DBF_TAG_SIZE) == 0 || strncmp(r->tag, "rels", ZFCP_DBF_TAG_SIZE) == 0 || strncmp(r->tag, "iels", ZFCP_DBF_TAG_SIZE) == 0) { @@ -1249,7 +1251,7 @@ int zfcp_adapter_debug_register(struct zfcp_adapter *adapter) char dbf_name[DEBUG_MAX_NAME_LEN]; /* debug feature area which records recovery activity */ - sprintf(dbf_name, "zfcp_%s_rec", zfcp_get_busid_by_adapter(adapter)); + sprintf(dbf_name, "zfcp_%s_rec", dev_name(&adapter->ccw_device->dev)); adapter->rec_dbf = debug_register(dbf_name, dbfsize, 1, sizeof(struct zfcp_rec_dbf_record)); if (!adapter->rec_dbf) @@ -1259,7 +1261,7 @@ int zfcp_adapter_debug_register(struct zfcp_adapter *adapter) debug_set_level(adapter->rec_dbf, 3); /* debug feature area which records HBA (FSF and QDIO) conditions */ - sprintf(dbf_name, "zfcp_%s_hba", zfcp_get_busid_by_adapter(adapter)); + sprintf(dbf_name, "zfcp_%s_hba", dev_name(&adapter->ccw_device->dev)); adapter->hba_dbf = debug_register(dbf_name, dbfsize, 1, sizeof(struct zfcp_hba_dbf_record)); if (!adapter->hba_dbf) @@ -1269,7 +1271,7 @@ int zfcp_adapter_debug_register(struct zfcp_adapter *adapter) debug_set_level(adapter->hba_dbf, 3); /* debug feature area which records SAN command failures and recovery */ - sprintf(dbf_name, "zfcp_%s_san", zfcp_get_busid_by_adapter(adapter)); + sprintf(dbf_name, "zfcp_%s_san", dev_name(&adapter->ccw_device->dev)); adapter->san_dbf = debug_register(dbf_name, dbfsize, 1, sizeof(struct zfcp_san_dbf_record)); if (!adapter->san_dbf) @@ -1279,7 +1281,7 @@ int zfcp_adapter_debug_register(struct zfcp_adapter *adapter) debug_set_level(adapter->san_dbf, 6); /* debug feature area which records SCSI command failures and recovery */ - sprintf(dbf_name, "zfcp_%s_scsi", zfcp_get_busid_by_adapter(adapter)); + sprintf(dbf_name, "zfcp_%s_scsi", dev_name(&adapter->ccw_device->dev)); adapter->scsi_dbf = debug_register(dbf_name, dbfsize, 1, sizeof(struct zfcp_scsi_dbf_record)); if (!adapter->scsi_dbf) diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h index 5d6b2dff855b..74998ff88e57 100644 --- a/drivers/s390/scsi/zfcp_dbf.h +++ b/drivers/s390/scsi/zfcp_dbf.h @@ -171,6 +171,7 @@ struct zfcp_san_dbf_record_ct_response { u8 reason_code; u8 expl; u8 vendor_unique; + u16 max_res_size; u32 len; } __attribute__ ((packed)); diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index e19e46ae4a68..510662783a6f 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -159,20 +159,6 @@ struct fcp_rscn_element { u32 nport_did:24; } __attribute__((packed)); -#define ZFCP_PORT_ADDRESS 0x0 -#define ZFCP_AREA_ADDRESS 0x1 -#define ZFCP_DOMAIN_ADDRESS 0x2 -#define ZFCP_FABRIC_ADDRESS 0x3 - -#define ZFCP_PORTS_RANGE_PORT 0xFFFFFF -#define ZFCP_PORTS_RANGE_AREA 0xFFFF00 -#define ZFCP_PORTS_RANGE_DOMAIN 0xFF0000 -#define ZFCP_PORTS_RANGE_FABRIC 0x000000 - -#define ZFCP_NO_PORTS_PER_AREA 0x100 -#define ZFCP_NO_PORTS_PER_DOMAIN 0x10000 -#define ZFCP_NO_PORTS_PER_FABRIC 0x1000000 - /* see fc-ph */ struct fcp_logo { u32 command; @@ -211,7 +197,6 @@ struct zfcp_ls_adisc { #define ZFCP_CT_UNABLE_TO_PERFORM_CMD 0x09 #define ZFCP_CT_GID_PN 0x0121 #define ZFCP_CT_GPN_FT 0x0172 -#define ZFCP_CT_MAX_SIZE 0x1020 #define ZFCP_CT_ACCEPT 0x8002 #define ZFCP_CT_REJECT 0x8001 @@ -258,7 +243,6 @@ struct zfcp_ls_adisc { /* remote port status */ #define ZFCP_STATUS_PORT_PHYS_OPEN 0x00000001 -#define ZFCP_STATUS_PORT_DID_DID 0x00000002 #define ZFCP_STATUS_PORT_PHYS_CLOSING 0x00000004 #define ZFCP_STATUS_PORT_NO_WWPN 0x00000008 #define ZFCP_STATUS_PORT_INVALID_WWPN 0x00000020 @@ -340,8 +324,6 @@ struct ct_iu_gid_pn_resp { * @wka_port: port where the request is sent to * @req: scatter-gather list for request * @resp: scatter-gather list for response - * @req_count: number of elements in request scatter-gather list - * @resp_count: number of elements in response scatter-gather list * @handler: handler function (called for response to the request) * @handler_data: data passed to handler function * @timeout: FSF timeout for this request @@ -352,8 +334,6 @@ struct zfcp_send_ct { struct zfcp_wka_port *wka_port; struct scatterlist *req; struct scatterlist *resp; - unsigned int req_count; - unsigned int resp_count; void (*handler)(unsigned long); unsigned long handler_data; int timeout; @@ -378,8 +358,6 @@ struct zfcp_gid_pn_data { * @d_id: destiniation id of port where request is sent to * @req: scatter-gather list for request * @resp: scatter-gather list for response - * @req_count: number of elements in request scatter-gather list - * @resp_count: number of elements in response scatter-gather list * @handler: handler function (called for response to the request) * @handler_data: data passed to handler function * @completion: completion for synchronization purposes @@ -392,8 +370,6 @@ struct zfcp_send_els { u32 d_id; struct scatterlist *req; struct scatterlist *resp; - unsigned int req_count; - unsigned int resp_count; void (*handler)(unsigned long); unsigned long handler_data; struct completion *completion; @@ -451,7 +427,6 @@ struct zfcp_latencies { }; struct zfcp_adapter { - struct list_head list; /* list of adapters */ atomic_t refcount; /* reference count */ wait_queue_head_t remove_wq; /* can be used to wait for refcount drop to zero */ @@ -593,16 +568,11 @@ struct zfcp_fsf_req { struct zfcp_data { struct scsi_host_template scsi_host_template; struct scsi_transport_template *scsi_transport_template; - struct list_head adapter_list_head; /* head of adapter list */ rwlock_t config_lock; /* serialises changes to adapter/port/unit lists */ struct semaphore config_sema; /* serialises configuration changes */ - atomic_t loglevel; /* current loglevel */ - char init_busid[20]; - u64 init_wwpn; - u64 init_fcp_lun; struct kmem_cache *fsf_req_qtcb_cache; struct kmem_cache *sr_buffer_cache; struct kmem_cache *gid_pn_cache; @@ -623,8 +593,6 @@ struct zfcp_fsf_req_qtcb { #define ZFCP_SET 0x00000100 #define ZFCP_CLEAR 0x00000200 -#define zfcp_get_busid_by_adapter(adapter) (dev_name(&adapter->ccw_device->dev)) - /* * Helper functions for request ID management. */ diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 4ed4950d994b..387a3af528ac 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -840,7 +840,6 @@ static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act) return ZFCP_ERP_FAILED; } port->d_id = adapter->peer_d_id; - atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status); return zfcp_erp_port_strategy_open_port(act); } @@ -871,12 +870,12 @@ static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act) case ZFCP_ERP_STEP_PORT_CLOSING: if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) return zfcp_erp_open_ptp_port(act); - if (!(p_status & ZFCP_STATUS_PORT_DID_DID)) { + if (!port->d_id) { queue_work(zfcp_data.work_queue, &port->gid_pn_work); return ZFCP_ERP_CONTINUES; } case ZFCP_ERP_STEP_NAMESERVER_LOOKUP: - if (!(p_status & ZFCP_STATUS_PORT_DID_DID)) { + if (!port->d_id) { if (p_status & (ZFCP_STATUS_PORT_INVALID_WWPN)) { zfcp_erp_port_failed(port, 26, NULL); return ZFCP_ERP_EXIT; @@ -888,7 +887,7 @@ static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act) case ZFCP_ERP_STEP_PORT_OPENING: /* D_ID might have changed during open */ if (p_status & ZFCP_STATUS_COMMON_OPEN) { - if (p_status & ZFCP_STATUS_PORT_DID_DID) + if (port->d_id) return ZFCP_ERP_SUCCEEDED; else { act->step = ZFCP_ERP_STEP_PORT_CLOSING; @@ -1385,6 +1384,7 @@ static int zfcp_erp_thread(void *data) struct list_head *next; struct zfcp_erp_action *act; unsigned long flags; + int ignore; daemonize("zfcperp%s", dev_name(&adapter->ccw_device->dev)); /* Block all signals */ @@ -1407,7 +1407,7 @@ static int zfcp_erp_thread(void *data) } zfcp_rec_dbf_event_thread_lock(4, adapter); - down_interruptible(&adapter->erp_ready_sem); + ignore = down_interruptible(&adapter->erp_ready_sem); zfcp_rec_dbf_event_thread_lock(5, adapter); } diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index f009f2a7ec3e..eabdfe24456e 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -11,6 +11,20 @@ #include "zfcp_ext.h" +enum rscn_address_format { + RSCN_PORT_ADDRESS = 0x0, + RSCN_AREA_ADDRESS = 0x1, + RSCN_DOMAIN_ADDRESS = 0x2, + RSCN_FABRIC_ADDRESS = 0x3, +}; + +static u32 rscn_range_mask[] = { + [RSCN_PORT_ADDRESS] = 0xFFFFFF, + [RSCN_AREA_ADDRESS] = 0xFFFF00, + [RSCN_DOMAIN_ADDRESS] = 0xFF0000, + [RSCN_FABRIC_ADDRESS] = 0x000000, +}; + struct ct_iu_gpn_ft_req { struct ct_hdr header; u8 flags; @@ -26,9 +40,12 @@ struct gpn_ft_resp_acc { u64 wwpn; } __attribute__ ((packed)); -#define ZFCP_GPN_FT_ENTRIES ((PAGE_SIZE - sizeof(struct ct_hdr)) \ - / sizeof(struct gpn_ft_resp_acc)) +#define ZFCP_CT_SIZE_ONE_PAGE (PAGE_SIZE - sizeof(struct ct_hdr)) +#define ZFCP_GPN_FT_ENTRIES (ZFCP_CT_SIZE_ONE_PAGE \ + / sizeof(struct gpn_ft_resp_acc)) #define ZFCP_GPN_FT_BUFFERS 4 +#define ZFCP_GPN_FT_MAX_SIZE (ZFCP_GPN_FT_BUFFERS * PAGE_SIZE \ + - sizeof(struct ct_hdr)) #define ZFCP_GPN_FT_MAX_ENTRIES ZFCP_GPN_FT_BUFFERS * (ZFCP_GPN_FT_ENTRIES + 1) struct ct_iu_gpn_ft_resp { @@ -160,22 +177,7 @@ static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req) for (i = 1; i < no_entries; i++) { /* skip head and start with 1st element */ fcp_rscn_element++; - switch (fcp_rscn_element->addr_format) { - case ZFCP_PORT_ADDRESS: - range_mask = ZFCP_PORTS_RANGE_PORT; - break; - case ZFCP_AREA_ADDRESS: - range_mask = ZFCP_PORTS_RANGE_AREA; - break; - case ZFCP_DOMAIN_ADDRESS: - range_mask = ZFCP_PORTS_RANGE_DOMAIN; - break; - case ZFCP_FABRIC_ADDRESS: - range_mask = ZFCP_PORTS_RANGE_FABRIC; - break; - default: - continue; - } + range_mask = rscn_range_mask[fcp_rscn_element->addr_format]; _zfcp_fc_incoming_rscn(fsf_req, range_mask, fcp_rscn_element); } schedule_work(&fsf_req->adapter->scan_work); @@ -266,7 +268,6 @@ static void zfcp_fc_ns_gid_pn_eval(unsigned long data) return; /* looks like a valid d_id */ port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK; - atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status); } int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action, @@ -284,8 +285,6 @@ int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action, gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT; gid_pn->ct.req = &gid_pn->req; gid_pn->ct.resp = &gid_pn->resp; - gid_pn->ct.req_count = 1; - gid_pn->ct.resp_count = 1; sg_init_one(&gid_pn->req, &gid_pn->ct_iu_req, sizeof(struct ct_iu_gid_pn_req)); sg_init_one(&gid_pn->resp, &gid_pn->ct_iu_resp, @@ -297,7 +296,7 @@ int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action, gid_pn->ct_iu_req.header.gs_subtype = ZFCP_CT_NAME_SERVER; gid_pn->ct_iu_req.header.options = ZFCP_CT_SYNCHRONOUS; gid_pn->ct_iu_req.header.cmd_rsp_code = ZFCP_CT_GID_PN; - gid_pn->ct_iu_req.header.max_res_size = ZFCP_CT_MAX_SIZE; + gid_pn->ct_iu_req.header.max_res_size = ZFCP_CT_SIZE_ONE_PAGE / 4; gid_pn->ct_iu_req.wwpn = erp_action->port->wwpn; init_completion(&compl_rec.done); @@ -407,8 +406,6 @@ static int zfcp_fc_adisc(struct zfcp_port *port) sg_init_one(adisc->els.resp, &adisc->ls_adisc_acc, sizeof(struct zfcp_ls_adisc)); - adisc->els.req_count = 1; - adisc->els.resp_count = 1; adisc->els.adapter = adapter; adisc->els.port = port; adisc->els.d_id = port->d_id; @@ -448,17 +445,17 @@ void zfcp_test_link(struct zfcp_port *port) zfcp_erp_port_forced_reopen(port, 0, 65, NULL); } -static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft) +static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft, int buf_num) { struct scatterlist *sg = &gpn_ft->sg_req; kfree(sg_virt(sg)); /* free request buffer */ - zfcp_sg_free_table(gpn_ft->sg_resp, ZFCP_GPN_FT_BUFFERS); + zfcp_sg_free_table(gpn_ft->sg_resp, buf_num); kfree(gpn_ft); } -static struct zfcp_gpn_ft *zfcp_alloc_sg_env(void) +static struct zfcp_gpn_ft *zfcp_alloc_sg_env(int buf_num) { struct zfcp_gpn_ft *gpn_ft; struct ct_iu_gpn_ft_req *req; @@ -475,8 +472,8 @@ static struct zfcp_gpn_ft *zfcp_alloc_sg_env(void) } sg_init_one(&gpn_ft->sg_req, req, sizeof(*req)); - if (zfcp_sg_setup_table(gpn_ft->sg_resp, ZFCP_GPN_FT_BUFFERS)) { - zfcp_free_sg_env(gpn_ft); + if (zfcp_sg_setup_table(gpn_ft->sg_resp, buf_num)) { + zfcp_free_sg_env(gpn_ft, buf_num); gpn_ft = NULL; } out: @@ -485,7 +482,8 @@ out: static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft, - struct zfcp_adapter *adapter) + struct zfcp_adapter *adapter, + int max_bytes) { struct zfcp_send_ct *ct = &gpn_ft->ct; struct ct_iu_gpn_ft_req *req = sg_virt(&gpn_ft->sg_req); @@ -498,8 +496,7 @@ static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft, req->header.gs_subtype = ZFCP_CT_NAME_SERVER; req->header.options = ZFCP_CT_SYNCHRONOUS; req->header.cmd_rsp_code = ZFCP_CT_GPN_FT; - req->header.max_res_size = (sizeof(struct gpn_ft_resp_acc) * - (ZFCP_GPN_FT_MAX_ENTRIES - 1)) >> 2; + req->header.max_res_size = max_bytes / 4; req->flags = 0; req->domain_id_scope = 0; req->area_id_scope = 0; @@ -512,8 +509,6 @@ static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft, ct->timeout = 10; ct->req = &gpn_ft->sg_req; ct->resp = gpn_ft->sg_resp; - ct->req_count = 1; - ct->resp_count = ZFCP_GPN_FT_BUFFERS; init_completion(&compl_rec.done); compl_rec.handler = NULL; @@ -540,7 +535,7 @@ static void zfcp_validate_port(struct zfcp_port *port) zfcp_port_dequeue(port); } -static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft) +static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries) { struct zfcp_send_ct *ct = &gpn_ft->ct; struct scatterlist *sg = gpn_ft->sg_resp; @@ -560,13 +555,17 @@ static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft) return -EIO; } - if (hdr->max_res_size) + if (hdr->max_res_size) { + dev_warn(&adapter->ccw_device->dev, + "The name server reported %d words residual data\n", + hdr->max_res_size); return -E2BIG; + } down(&zfcp_data.config_sema); /* first entry is the header */ - for (x = 1; x < ZFCP_GPN_FT_MAX_ENTRIES && !last; x++) { + for (x = 1; x < max_entries && !last; x++) { if (x % (ZFCP_GPN_FT_ENTRIES + 1)) acc++; else @@ -589,7 +588,6 @@ static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft) } port = zfcp_port_enqueue(adapter, acc->wwpn, - ZFCP_STATUS_PORT_DID_DID | ZFCP_STATUS_COMMON_NOESC, d_id); if (IS_ERR(port)) ret = PTR_ERR(port); @@ -612,6 +610,12 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter) { int ret, i; struct zfcp_gpn_ft *gpn_ft; + int chain, max_entries, buf_num, max_bytes; + + chain = adapter->adapter_features & FSF_FEATURE_ELS_CT_CHAINED_SBALS; + buf_num = chain ? ZFCP_GPN_FT_BUFFERS : 1; + max_entries = chain ? ZFCP_GPN_FT_MAX_ENTRIES : ZFCP_GPN_FT_ENTRIES; + max_bytes = chain ? ZFCP_GPN_FT_MAX_SIZE : ZFCP_CT_SIZE_ONE_PAGE; if (fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPORT) return 0; @@ -620,23 +624,23 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter) if (ret) return ret; - gpn_ft = zfcp_alloc_sg_env(); + gpn_ft = zfcp_alloc_sg_env(buf_num); if (!gpn_ft) { ret = -ENOMEM; goto out; } for (i = 0; i < 3; i++) { - ret = zfcp_scan_issue_gpn_ft(gpn_ft, adapter); + ret = zfcp_scan_issue_gpn_ft(gpn_ft, adapter, max_bytes); if (!ret) { - ret = zfcp_scan_eval_gpn_ft(gpn_ft); + ret = zfcp_scan_eval_gpn_ft(gpn_ft, max_entries); if (ret == -EAGAIN) ssleep(1); else break; } } - zfcp_free_sg_env(gpn_ft); + zfcp_free_sg_env(gpn_ft, buf_num); out: zfcp_wka_port_put(&adapter->nsp); return ret; diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 9c72e083559d..e6416f8541b0 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -644,38 +644,38 @@ static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req) } } -static int zfcp_fsf_sbal_check(struct zfcp_adapter *adapter) +static int zfcp_fsf_sbal_available(struct zfcp_adapter *adapter) { - struct zfcp_qdio_queue *req_q = &adapter->req_q; - - spin_lock_bh(&adapter->req_q_lock); - if (atomic_read(&req_q->count)) + if (atomic_read(&adapter->req_q.count) > 0) return 1; - spin_unlock_bh(&adapter->req_q_lock); + atomic_inc(&adapter->qdio_outb_full); return 0; } -static int zfcp_fsf_sbal_available(struct zfcp_adapter *adapter) -{ - unsigned int count = atomic_read(&adapter->req_q.count); - if (!count) - atomic_inc(&adapter->qdio_outb_full); - return count > 0; -} - static int zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter) + __releases(&adapter->req_q_lock) + __acquires(&adapter->req_q_lock) { + struct zfcp_qdio_queue *req_q = &adapter->req_q; long ret; + if (atomic_read(&req_q->count) <= -REQUEST_LIST_SIZE) + return -EIO; + if (atomic_read(&req_q->count) > 0) + return 0; + + atomic_dec(&req_q->count); spin_unlock_bh(&adapter->req_q_lock); ret = wait_event_interruptible_timeout(adapter->request_wq, - zfcp_fsf_sbal_check(adapter), 5 * HZ); + atomic_read(&req_q->count) >= 0, + 5 * HZ); + spin_lock_bh(&adapter->req_q_lock); + atomic_inc(&req_q->count); + if (ret > 0) return 0; if (!ret) atomic_inc(&adapter->qdio_outb_full); - - spin_lock_bh(&adapter->req_q_lock); return -EIO; } @@ -1013,12 +1013,29 @@ skip_fsfstatus: send_ct->handler(send_ct->handler_data); } -static int zfcp_fsf_setup_sbals(struct zfcp_fsf_req *req, - struct scatterlist *sg_req, - struct scatterlist *sg_resp, int max_sbals) +static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req, + struct scatterlist *sg_req, + struct scatterlist *sg_resp, + int max_sbals) { + struct qdio_buffer_element *sbale = zfcp_qdio_sbale_req(req); + u32 feat = req->adapter->adapter_features; int bytes; + if (!(feat & FSF_FEATURE_ELS_CT_CHAINED_SBALS)) { + if (sg_req->length > PAGE_SIZE || sg_resp->length > PAGE_SIZE || + !sg_is_last(sg_req) || !sg_is_last(sg_resp)) + return -EOPNOTSUPP; + + sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ; + sbale[2].addr = sg_virt(sg_req); + sbale[2].length = sg_req->length; + sbale[3].addr = sg_virt(sg_resp); + sbale[3].length = sg_resp->length; + sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY; + return 0; + } + bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ, sg_req, max_sbals); if (bytes <= 0) @@ -1060,8 +1077,8 @@ int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, goto out; } - ret = zfcp_fsf_setup_sbals(req, ct->req, ct->resp, - FSF_MAX_SBALS_PER_REQ); + ret = zfcp_fsf_setup_ct_els_sbals(req, ct->req, ct->resp, + FSF_MAX_SBALS_PER_REQ); if (ret) goto failed_send; @@ -1171,7 +1188,7 @@ int zfcp_fsf_send_els(struct zfcp_send_els *els) goto out; } - ret = zfcp_fsf_setup_sbals(req, els->req, els->resp, 2); + ret = zfcp_fsf_setup_ct_els_sbals(req, els->req, els->resp, 2); if (ret) goto failed_send; @@ -1406,13 +1423,7 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) switch (header->fsf_status_qual.word[0]) { case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: - req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; case FSF_SQ_NO_RETRY_POSSIBLE: - dev_warn(&req->adapter->ccw_device->dev, - "Remote port 0x%016Lx could not be opened\n", - (unsigned long long)port->wwpn); - zfcp_erp_port_failed(port, 32, req); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; } @@ -1440,10 +1451,10 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) * Alternately, an ADISC/PDISC ELS should suffice, as well. */ plogi = (struct fsf_plogi *) req->qtcb->bottom.support.els; - if (req->qtcb->bottom.support.els1_length >= sizeof(*plogi)) { + if (req->qtcb->bottom.support.els1_length >= + FSF_PLOGI_MIN_LEN) { if (plogi->serv_param.wwpn != port->wwpn) - atomic_clear_mask(ZFCP_STATUS_PORT_DID_DID, - &port->status); + port->d_id = 0; else { port->wwnn = plogi->serv_param.wwnn; zfcp_fc_plogi_evaluate(port, plogi); @@ -1907,7 +1918,7 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req) dev_err(&adapter->ccw_device->dev, "Shared read-write access not " "supported (unit 0x%016Lx, port " - "0x%016Lx\n)", + "0x%016Lx)\n", (unsigned long long)unit->fcp_lun, (unsigned long long)unit->port->wwpn); zfcp_erp_unit_failed(unit, 36, req); diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h index fa2a31780611..8bb200252347 100644 --- a/drivers/s390/scsi/zfcp_fsf.h +++ b/drivers/s390/scsi/zfcp_fsf.h @@ -164,6 +164,7 @@ #define FSF_FEATURE_LUN_SHARING 0x00000004 #define FSF_FEATURE_NOTIFICATION_LOST 0x00000008 #define FSF_FEATURE_HBAAPI_MANAGEMENT 0x00000010 +#define FSF_FEATURE_ELS_CT_CHAINED_SBALS 0x00000020 #define FSF_FEATURE_UPDATE_ALERT 0x00000100 #define FSF_FEATURE_MEASUREMENT_DATA 0x00000200 @@ -322,6 +323,7 @@ struct fsf_nport_serv_param { u8 vendor_version_level[16]; } __attribute__ ((packed)); +#define FSF_PLOGI_MIN_LEN 112 struct fsf_plogi { u32 code; struct fsf_nport_serv_param serv_param; diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index d3b55fb66f13..33e0a206a0a4 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -112,7 +112,7 @@ static void zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, * corruption and must stop the machine immediatly. */ panic("error: unknown request id (%lx) on adapter %s.\n", - req_id, zfcp_get_busid_by_adapter(adapter)); + req_id, dev_name(&adapter->ccw_device->dev)); zfcp_reqlist_remove(adapter, fsf_req); spin_unlock_irqrestore(&adapter->req_list_lock, flags); @@ -392,7 +392,7 @@ int zfcp_qdio_allocate(struct zfcp_adapter *adapter) init_data->cdev = adapter->ccw_device; init_data->q_format = QDIO_ZFCP_QFMT; - memcpy(init_data->adapter_name, zfcp_get_busid_by_adapter(adapter), 8); + memcpy(init_data->adapter_name, dev_name(&adapter->ccw_device->dev), 8); ASCEBC(init_data->adapter_name, 8); init_data->qib_param_field_format = 0; init_data->qib_param_field = NULL; |