From: Martin Schwidefsky - Adapt to notify api change in cio. - Add missing unregister_reboot_notifier() for error path. - Fix infinite error recovery escalation for certain port failures. - Fix reference counting. - Use GFP_ATOMIC for kmalloc while holding a spinlock. - Don't open adapter/port if unit/port is removed from configuration after it has already been closed. - Don't establish qdio queues if a port/unit is going to be removed. - Shutdown ports and units before removing them. - Use schedule_work for scsi_add_device. - Don't reopen nameserver port when an rscn was received. - Don't call scsi_done twice in zfcp_fsf_send_fcp_command_task_handler. - Get rid of scsi fake queue, scsi_reqs_active and scsi_reqs_active_wq. - Get rid of unused adapter status. - Allow enabling of scsi devices at boot time with zfcp_dev parameter. - Change name prefix from sg to sg_list for functions which work with the struct sg_list. - Don't call scsi_add_device from zfcp error recovery thread to avoid a deadlock if a scsi command sent during scsi_add_device fails. - Fix scsi i/o stall due to missing local-link-up event. --- 25-akpm/drivers/s390/scsi/zfcp_aux.c | 191 +++++++++++++------- 25-akpm/drivers/s390/scsi/zfcp_ccw.c | 14 - 25-akpm/drivers/s390/scsi/zfcp_def.h | 27 +- 25-akpm/drivers/s390/scsi/zfcp_erp.c | 132 ++++++++++++-- 25-akpm/drivers/s390/scsi/zfcp_ext.h | 10 - 25-akpm/drivers/s390/scsi/zfcp_fsf.c | 122 +++++++------ 25-akpm/drivers/s390/scsi/zfcp_fsf.h | 3 25-akpm/drivers/s390/scsi/zfcp_qdio.c | 52 +++-- 25-akpm/drivers/s390/scsi/zfcp_scsi.c | 228 ++----------------------- 25-akpm/drivers/s390/scsi/zfcp_sysfs_adapter.c | 12 - 25-akpm/drivers/s390/scsi/zfcp_sysfs_port.c | 28 ++- 25-akpm/drivers/s390/scsi/zfcp_sysfs_unit.c | 14 + 12 files changed, 431 insertions(+), 402 deletions(-) diff -puN drivers/s390/scsi/zfcp_aux.c~s390-07-zfcp-host-adapter drivers/s390/scsi/zfcp_aux.c --- 25/drivers/s390/scsi/zfcp_aux.c~s390-07-zfcp-host-adapter Thu Jan 8 14:11:34 2004 +++ 25-akpm/drivers/s390/scsi/zfcp_aux.c Thu Jan 8 14:11:34 2004 @@ -28,7 +28,7 @@ */ /* this drivers version (do not edit !!! generated and updated by cvs) */ -#define ZFCP_AUX_REVISION "$Revision: 1.65 $" +#define ZFCP_AUX_REVISION "$Revision: 1.79 $" /********************** INCLUDES *********************************************/ @@ -285,7 +285,7 @@ zfcp_cmd_dbf_event_scsi(const char *text debug_event(adapter->cmd_dbf, level, &scsi_cmnd->result, sizeof (u32)); debug_event(adapter->cmd_dbf, level, &scsi_cmnd, sizeof (unsigned long)); - if (fsf_req) { + if (likely(fsf_req)) { debug_event(adapter->cmd_dbf, level, &fsf_req, sizeof (unsigned long)); debug_event(adapter->cmd_dbf, level, &fsf_req->seq_no, @@ -316,6 +316,89 @@ zfcp_in_els_dbf_event(struct zfcp_adapte #endif } +#ifndef MODULE +/** + * zfcp_device_setup - setup function + * @str: pointer to parameter string + * + * Parse the kernel parameter string "zfcp_device=..." + */ +static int __init +zfcp_device_setup(char *str) +{ + char *tmp; + + tmp = strchr(str, ','); + if (!tmp) + goto err_out; + *tmp++ = '\0'; + strncpy(zfcp_data.init_busid, str, BUS_ID_SIZE); + zfcp_data.init_busid[BUS_ID_SIZE-1] = '\0'; + + zfcp_data.init_wwpn = simple_strtoull(tmp, &tmp, 0); + if (*tmp++ != ',') + goto err_out; + if (*tmp == '\0') + goto err_out; + + zfcp_data.init_fcp_lun = simple_strtoull(tmp, &tmp, 0); + if (*tmp != '\0') + goto err_out; + + zfcp_data.init_is_valid = 1; + goto out; + + err_out: + ZFCP_LOG_NORMAL("Parse error for parameter string %s\n", str); + out: + return 1; +} + +__setup("zfcp_device=", zfcp_device_setup); + +static void __init +zfcp_init_device_configure(void) +{ + int found = 0; + unsigned long flags; + struct zfcp_adapter *adapter; + struct zfcp_port *port; + struct zfcp_unit *unit; + + down(&zfcp_data.config_sema); + read_lock_irqsave(&zfcp_data.config_lock, flags); + list_for_each_entry(adapter, &zfcp_data.adapter_list_head, list) + if (strcmp(zfcp_data.init_busid, + zfcp_get_busid_by_adapter(adapter)) == 0) { + zfcp_adapter_get(adapter); + found = 1; + break; + } + read_unlock_irqrestore(&zfcp_data.config_lock, flags); + if (!found) + goto out_adapter; + port = zfcp_port_enqueue(adapter, zfcp_data.init_wwpn, 0); + if (!port) + goto out_port; + unit = zfcp_unit_enqueue(port, zfcp_data.init_fcp_lun); + if (!unit) + goto out_unit; + up(&zfcp_data.config_sema); + ccw_device_set_online(adapter->ccw_device); + down(&zfcp_data.config_sema); + wait_event(unit->scsi_add_wq, atomic_read(&unit->scsi_add_work) == 0); + zfcp_unit_put(unit); + out_unit: + zfcp_port_put(port); + out_port: + zfcp_adapter_put(adapter); + out_adapter: + up(&zfcp_data.config_sema); + return; +} + +#endif /* #ifndef MODULE */ + static int __init zfcp_module_init(void) { @@ -357,9 +440,15 @@ zfcp_module_init(void) ZFCP_LOG_NORMAL("Registering with common I/O layer failed.\n"); goto out_ccw_register; } +#ifndef MODULE + if (zfcp_data.init_is_valid) + zfcp_init_device_configure(); +#endif + goto out; out_ccw_register: + unregister_reboot_notifier(&zfcp_data.reboot_notifier); #ifdef ZFCP_STAT_REQSIZES zfcp_statistics_clear_all(); #endif @@ -391,13 +480,8 @@ int zfcp_reboot_handler(struct notifier_block *notifier, unsigned long code, void *ptr) { - int retval = NOTIFY_DONE; - - /* block access to config (for rest of lifetime of this Linux) */ - down(&zfcp_data.config_sema); - zfcp_erp_adapter_shutdown_all(); - - return retval; + zfcp_ccw_unregister(); + return NOTIFY_DONE; } #undef ZFCP_LOG_AREA @@ -503,6 +587,7 @@ zfcp_unit_enqueue(struct zfcp_port *port return NULL; memset(unit, 0, sizeof (struct zfcp_unit)); + init_waitqueue_head(&unit->scsi_add_wq); /* initialise reference count stuff */ atomic_set(&unit->refcount, 0); init_waitqueue_head(&unit->remove_wq); @@ -571,6 +656,7 @@ zfcp_unit_enqueue(struct zfcp_port *port write_unlock_irq(&zfcp_data.config_lock); port->units++; + zfcp_port_get(port); return unit; } @@ -763,17 +849,10 @@ zfcp_adapter_enqueue(struct ccw_device * /* initialize abort lock */ rwlock_init(&adapter->abort_lock); - /* initialise scsi faking structures */ - rwlock_init(&adapter->fake_list_lock); - init_timer(&adapter->fake_scsi_timer); - /* initialise some erp stuff */ init_waitqueue_head(&adapter->erp_thread_wqh); init_waitqueue_head(&adapter->erp_done_wqh); - /* notification when there are no outstanding SCSI commands */ - init_waitqueue_head(&adapter->scsi_reqs_active_wq); - /* initialize lock of associated request queue */ rwlock_init(&adapter->request_queue.queue_lock); @@ -904,7 +983,6 @@ zfcp_adapter_enqueue(struct ccw_device * /* put allocated adapter at list tail */ write_lock_irq(&zfcp_data.config_lock); atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); - atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &adapter->status); list_add_tail(&adapter->list, &zfcp_data.adapter_list_head); write_unlock_irq(&zfcp_data.config_lock); @@ -1149,6 +1227,7 @@ zfcp_port_enqueue(struct zfcp_adapter *a write_unlock_irq(&zfcp_data.config_lock); adapter->ports++; + zfcp_adapter_get(adapter); return port; } @@ -1193,7 +1272,6 @@ zfcp_nameserver_enqueue(struct zfcp_adap /* set special D_ID */ port->d_id = ZFCP_DID_NAMESERVER; adapter->nameserver_port = port; - zfcp_adapter_get(adapter); zfcp_port_put(port); return 0; @@ -1216,9 +1294,9 @@ zfcp_fsf_incoming_els_rscn(struct zfcp_a struct fcp_rscn_head *fcp_rscn_head; struct fcp_rscn_element *fcp_rscn_element; struct zfcp_port *port; - int i; - int reopen_unknown = 0; - int no_entries; + u16 i; + u16 no_entries; + u32 range_mask; unsigned long flags; fcp_rscn_head = (struct fcp_rscn_head *) status_buffer->payload; @@ -1232,56 +1310,57 @@ zfcp_fsf_incoming_els_rscn(struct zfcp_a debug_text_event(adapter->erp_dbf, 1, "unsol_els_rscn:"); for (i = 1; i < no_entries; i++) { - int known; - int range_mask; - int no_notifications; - - range_mask = 0; - no_notifications = 0; - known = 0; /* skip head and start with 1st element */ fcp_rscn_element++; switch (fcp_rscn_element->addr_format) { case ZFCP_PORT_ADDRESS: ZFCP_LOG_FLAGS(1, "ZFCP_PORT_ADDRESS\n"); range_mask = ZFCP_PORTS_RANGE_PORT; - no_notifications = 1; break; case ZFCP_AREA_ADDRESS: ZFCP_LOG_FLAGS(1, "ZFCP_AREA_ADDRESS\n"); - /* skip head and start with 1st element */ range_mask = ZFCP_PORTS_RANGE_AREA; - no_notifications = ZFCP_NO_PORTS_PER_AREA; break; case ZFCP_DOMAIN_ADDRESS: ZFCP_LOG_FLAGS(1, "ZFCP_DOMAIN_ADDRESS\n"); range_mask = ZFCP_PORTS_RANGE_DOMAIN; - no_notifications = ZFCP_NO_PORTS_PER_DOMAIN; break; case ZFCP_FABRIC_ADDRESS: ZFCP_LOG_FLAGS(1, "ZFCP_FABRIC_ADDRESS\n"); range_mask = ZFCP_PORTS_RANGE_FABRIC; - no_notifications = ZFCP_NO_PORTS_PER_FABRIC; break; default: - /* cannot happen */ - break; + ZFCP_LOG_INFO("Received RSCN with unknown " + "address format.\n"); + continue; } read_lock_irqsave(&zfcp_data.config_lock, flags); list_for_each_entry(port, &adapter->port_list_head, list) { + if (atomic_test_mask + (ZFCP_STATUS_PORT_NAMESERVER, &port->status)) + continue; /* Do we know this port? If not skip it. */ if (!atomic_test_mask - (ZFCP_STATUS_PORT_DID_DID, &port->status)) + (ZFCP_STATUS_PORT_DID_DID, &port->status)) { + ZFCP_LOG_INFO + ("Received state change notification." + "Trying to open the port with wwpn " + "0x%Lx. Hope it's there now.\n", + port->wwpn); + debug_text_event(adapter->erp_dbf, 1, + "unsol_els_rscnu:"); + zfcp_erp_port_reopen(port, + ZFCP_STATUS_COMMON_ERP_FAILED); continue; + } + /* * FIXME: race: d_id might being invalidated * (...DID_DID reset) */ if ((port->d_id & range_mask) == (fcp_rscn_element->nport_did & range_mask)) { - known++; - ZFCP_LOG_TRACE("known=%d, reopen did 0x%x\n", - known, + ZFCP_LOG_TRACE("reopen did 0x%x\n", fcp_rscn_element->nport_did); /* * Unfortunately, an RSCN does not specify the @@ -1303,36 +1382,6 @@ zfcp_fsf_incoming_els_rscn(struct zfcp_a } } read_unlock_irqrestore(&zfcp_data.config_lock, flags); - ZFCP_LOG_TRACE("known %d, no_notifications %d\n", - known, no_notifications); - if (known < no_notifications) { - ZFCP_LOG_DEBUG - ("At least one unknown port changed state. " - "Unknown ports need to be reopened.\n"); - reopen_unknown = 1; - } - } // for (i=1; i < no_entries; i++) - - if (reopen_unknown) { - ZFCP_LOG_DEBUG("At least one unknown did " - "underwent a state change.\n"); - read_lock_irqsave(&zfcp_data.config_lock, flags); - list_for_each_entry(port, &adapter->port_list_head, list) { - if (!atomic_test_mask((ZFCP_STATUS_PORT_DID_DID - | ZFCP_STATUS_PORT_NAMESERVER), - &port->status)) { - ZFCP_LOG_INFO - ("Received state change notification." - "Trying to open the port with wwpn " - "0x%Lx. Hope it's there now.\n", - port->wwpn); - debug_text_event(adapter->erp_dbf, 1, - "unsol_els_rscnu:"); - zfcp_erp_port_reopen(port, - ZFCP_STATUS_COMMON_ERP_FAILED); - } - } - read_unlock_irqrestore(&zfcp_data.config_lock, flags); } } @@ -1469,7 +1518,7 @@ zfcp_get_nameserver_buffers(struct zfcp_ struct zfcp_adapter *adapter = fsf_req->adapter; int retval = 0; - data->outbuf = kmalloc(2 * sizeof (struct fc_ct_iu), GFP_KERNEL); + data->outbuf = kmalloc(2 * sizeof (struct fc_ct_iu), GFP_ATOMIC); if (data->outbuf) { memset(data->outbuf, 0, 2 * sizeof (struct fc_ct_iu)); } else { @@ -1479,7 +1528,7 @@ zfcp_get_nameserver_buffers(struct zfcp_ "adapter %s directly.. trying emergency pool\n", zfcp_get_busid_by_adapter(adapter)); data->outbuf = - mempool_alloc(adapter->pool.nameserver, GFP_KERNEL); + mempool_alloc(adapter->pool.nameserver, GFP_ATOMIC); if (!data->outbuf) { ZFCP_LOG_DEBUG ("Out of memory. Could not get emergency " diff -puN drivers/s390/scsi/zfcp_ccw.c~s390-07-zfcp-host-adapter drivers/s390/scsi/zfcp_ccw.c --- 25/drivers/s390/scsi/zfcp_ccw.c~s390-07-zfcp-host-adapter Thu Jan 8 14:11:34 2004 +++ 25-akpm/drivers/s390/scsi/zfcp_ccw.c Thu Jan 8 14:11:34 2004 @@ -25,7 +25,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#define ZFCP_CCW_C_REVISION "$Revision: 1.33 $" +#define ZFCP_CCW_C_REVISION "$Revision: 1.36 $" #include #include @@ -37,7 +37,7 @@ #define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_CONFIG static int zfcp_ccw_probe(struct ccw_device *); -static int zfcp_ccw_remove(struct ccw_device *); +static void zfcp_ccw_remove(struct ccw_device *); static int zfcp_ccw_set_online(struct ccw_device *); static int zfcp_ccw_set_offline(struct ccw_device *); @@ -90,16 +90,17 @@ zfcp_ccw_probe(struct ccw_device *ccw_de * * This function gets called by the common i/o layer and removes an adapter * from the system. Task of this function is to get rid of all units and - * ports that belong to this adapter. And addition all resources of this + * ports that belong to this adapter. And in addition all resources of this * adapter will be freed too. */ -static int +static void zfcp_ccw_remove(struct ccw_device *ccw_device) { struct zfcp_adapter *adapter; struct zfcp_port *port, *p; struct zfcp_unit *unit, *u; + ccw_device_set_offline(ccw_device); down(&zfcp_data.config_sema); adapter = dev_get_drvdata(&ccw_device->dev); @@ -119,16 +120,18 @@ zfcp_ccw_remove(struct ccw_device *ccw_d list_for_each_entry_safe(port, p, &adapter->port_remove_lh, list) { list_for_each_entry_safe(unit, u, &port->unit_remove_lh, list) { zfcp_unit_wait(unit); + zfcp_sysfs_unit_remove_files(&unit->sysfs_device); device_unregister(&unit->sysfs_device); } zfcp_port_wait(port); + zfcp_sysfs_port_remove_files(&port->sysfs_device, + atomic_read(&port->status)); device_unregister(&port->sysfs_device); } zfcp_adapter_wait(adapter); zfcp_adapter_dequeue(adapter); up(&zfcp_data.config_sema); - return 0; } /** @@ -155,6 +158,7 @@ zfcp_ccw_set_online(struct ccw_device *c zfcp_erp_modify_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED); + zfcp_erp_wait(adapter); out: up(&zfcp_data.config_sema); return retval; diff -puN drivers/s390/scsi/zfcp_def.h~s390-07-zfcp-host-adapter drivers/s390/scsi/zfcp_def.h --- 25/drivers/s390/scsi/zfcp_def.h~s390-07-zfcp-host-adapter Thu Jan 8 14:11:34 2004 +++ 25-akpm/drivers/s390/scsi/zfcp_def.h Thu Jan 8 14:11:34 2004 @@ -31,10 +31,8 @@ #ifndef ZFCP_DEF_H #define ZFCP_DEF_H -#ifdef __KERNEL__ - /* this drivers version (do not edit !!! generated and updated by cvs) */ -#define ZFCP_DEF_REVISION "$Revision: 1.41 $" +#define ZFCP_DEF_REVISION "$Revision: 1.48 $" /*************************** INCLUDES *****************************************/ @@ -64,7 +62,6 @@ typedef u32 scsi_id_t; typedef u32 scsi_lun_t; -#define ZFCP_FAKE_SCSI_COMPLETION_TIME (HZ / 3) #define ZFCP_ERP_SCSI_LOW_MEM_TIMEOUT (100*HZ) #define ZFCP_SCSI_ER_TIMEOUT (100*HZ) #define ZFCP_SCSI_HOST_FLUSH_TIMEOUT (1*HZ) @@ -470,7 +467,6 @@ extern u32 flags_dump; #define ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL 0x00000080 #define ZFCP_STATUS_ADAPTER_ERP_PENDING 0x00000100 #define ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED 0x00000200 -#define ZFCP_STATUS_ADAPTER_QUEUECOMMAND_BLOCK 0x00000400 #define ZFCP_STATUS_ADAPTER_SCSI_UP \ (ZFCP_STATUS_COMMON_UNBLOCKED | \ @@ -676,10 +672,7 @@ struct zfcp_adapter { u32 hydra_version; /* Hydra version */ u32 fsf_lic_version; struct Scsi_Host *scsi_host; /* Pointer to mid-layer */ - Scsi_Cmnd *first_fake_cmnd; /* Packets in flight list */ - rwlock_t fake_list_lock; /* Lock for the above */ - struct timer_list fake_scsi_timer; /* Starts processing of - faked commands */ + unsigned char name[9]; struct list_head port_list_head; /* remote port list */ struct list_head port_remove_lh; /* head of ports to be @@ -692,9 +685,6 @@ struct zfcp_adapter { rwlock_t fsf_req_list_lock; /* lock for ops on list of FSF requests */ atomic_t fsf_reqs_active; /* # active FSF reqs */ - atomic_t scsi_reqs_active; /* # active SCSI reqs */ - wait_queue_head_t scsi_reqs_active_wq; /* can be used to wait for - fsf_reqs_active chngs */ struct zfcp_qdio_queue request_queue; /* request queue */ u32 fsf_req_seq_no; /* FSF cmnd seq number */ wait_queue_head_t request_wq; /* can be used to wait for @@ -765,6 +755,8 @@ struct zfcp_unit { struct zfcp_erp_action erp_action; /* pending error recovery */ atomic_t erp_counter; struct device sysfs_device; /* sysfs device */ + atomic_t scsi_add_work; /* used to synchronize */ + wait_queue_head_t scsi_add_wq; /* wait for scsi_add_device */ }; /* FSF request */ @@ -809,6 +801,14 @@ struct zfcp_data { struct notifier_block reboot_notifier; /* used to register cleanup functions */ atomic_t loglevel; /* current loglevel */ +#ifndef MODULE /* initial parameters + needed if ipl from a + scsi device is wanted */ + char init_busid[BUS_ID_SIZE]; + wwn_t init_wwpn; + fcp_lun_t init_fcp_lun; + int init_is_valid; +#endif #ifdef ZFCP_STAT_REQSIZES /* Statistical accounting of processed data */ struct list_head read_req_head; @@ -857,7 +857,7 @@ struct zfcp_statistics { #ifndef atomic_test_mask #define atomic_test_mask(mask, target) \ - (atomic_read(target) & mask) + ((atomic_read(target) & mask) == mask) #endif extern void _zfcp_hex_dump(char *, int); @@ -957,5 +957,4 @@ zfcp_adapter_wait(struct zfcp_adapter *a wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0); } -#endif /* __KERNEL_- */ #endif /* ZFCP_DEF_H */ diff -puN drivers/s390/scsi/zfcp_erp.c~s390-07-zfcp-host-adapter drivers/s390/scsi/zfcp_erp.c --- 25/drivers/s390/scsi/zfcp_erp.c~s390-07-zfcp-host-adapter Thu Jan 8 14:11:34 2004 +++ 25-akpm/drivers/s390/scsi/zfcp_erp.c Thu Jan 8 14:11:34 2004 @@ -30,7 +30,7 @@ #define ZFCP_LOG_AREA ZFCP_LOG_AREA_ERP #define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_ERP /* this drivers version (do not edit !!! generated and updated by cvs) */ -#define ZFCP_ERP_REVISION "$Revision: 1.33 $" +#define ZFCP_ERP_REVISION "$Revision: 1.39 $" #include "zfcp_ext.h" @@ -108,6 +108,9 @@ static int zfcp_erp_action_dismiss(struc static int zfcp_erp_action_enqueue(int, struct zfcp_adapter *, struct zfcp_port *, struct zfcp_unit *); static int zfcp_erp_action_dequeue(struct zfcp_erp_action *); +static void zfcp_erp_action_cleanup(int, struct zfcp_adapter *, + struct zfcp_port *, struct zfcp_unit *, + int); static void zfcp_erp_action_ready(struct zfcp_erp_action *); static int zfcp_erp_action_exists(struct zfcp_erp_action *); @@ -1160,6 +1163,9 @@ zfcp_erp_strategy(struct zfcp_erp_action write_unlock(&adapter->erp_lock); read_unlock_irqrestore(&zfcp_data.config_lock, flags); + if (retval != ZFCP_ERP_CONTINUES) + zfcp_erp_action_cleanup(action, adapter, port, unit, retval); + /* * a few tasks remain when the erp queues are empty * (don't do that if the last action evaluated was dismissed @@ -1451,6 +1457,66 @@ zfcp_erp_strategy_statechange_detected(a !(ZFCP_STATUS_ERP_CLOSE_ONLY & erp_status)); } +/** + * zfcp_erp_scsi_add_device + * @data: pointer to a struct zfcp_unit + * + * Registers a logical unit with the SCSI stack. + */ +static void +zfcp_erp_scsi_add_device(void *data) +{ + struct { + struct zfcp_unit *unit; + struct work_struct work; + } *p; + + p = data; + scsi_add_device(p->unit->port->adapter->scsi_host, + 0, p->unit->port->scsi_id, p->unit->scsi_lun); + atomic_set(&p->unit->scsi_add_work, 0); + wake_up(&p->unit->scsi_add_wq); + zfcp_unit_put(p->unit); + kfree(p); +} + +/** + * zfcp_erp_schedule_work + * @unit: pointer to unit which should be registered with SCSI stack + * + * Schedules work which registers a unit with the SCSI stack + */ +static int +zfcp_erp_schedule_work(struct zfcp_unit *unit) +{ + struct { + struct zfcp_unit * unit; + struct work_struct work; + } *p; + + if (atomic_compare_and_swap(0, 1, &unit->scsi_add_work)) + return 0; + + if ((p = kmalloc(sizeof(*p), GFP_KERNEL)) == NULL) { + ZFCP_LOG_NORMAL("error: Out of resources. Could not register " + "the FCP-LUN 0x%Lx connected to " + "the port with WWPN 0x%Lx connected to " + "the adapter %s with the SCSI stack.\n", + unit->fcp_lun, + unit->port->wwpn, + zfcp_get_busid_by_unit(unit)); + atomic_set(&p->unit->scsi_add_work, 0); + return -ENOMEM; + } + + zfcp_unit_get(unit); + memset(p, 0, sizeof(*p)); + INIT_WORK(&p->work, zfcp_erp_scsi_add_device, p); + p->unit = unit; + schedule_work(&p->work); + return 0; +} + /* * function: * @@ -1468,10 +1534,6 @@ zfcp_erp_strategy_check_unit(struct zfcp if (result == ZFCP_ERP_SUCCEEDED) { atomic_set(&unit->erp_counter, 0); zfcp_erp_unit_unblock(unit); - /* register unit with scsi stack */ - if (!unit->device) - scsi_add_device(unit->port->adapter->scsi_host, - 0, unit->port->scsi_id, unit->scsi_lun); } else { /* ZFCP_ERP_FAILED or ZFCP_ERP_EXIT */ atomic_inc(&unit->erp_counter); @@ -1773,9 +1835,8 @@ zfcp_erp_port_reopen_all_internal(struct struct zfcp_port *port; list_for_each_entry(port, &adapter->port_list_head, list) - if (atomic_test_mask(ZFCP_STATUS_PORT_NAMESERVER, &port->status) - != ZFCP_STATUS_PORT_NAMESERVER) - zfcp_erp_port_reopen_internal(port, clear_mask); + if (!atomic_test_mask(ZFCP_STATUS_PORT_NAMESERVER, &port->status)) + zfcp_erp_port_reopen_internal(port, clear_mask); return retval; } @@ -2333,8 +2394,8 @@ zfcp_erp_port_forced_strategy(struct zfc * open flag is unset - however, this is for readabilty ... */ if (atomic_test_mask((ZFCP_STATUS_PORT_PHYS_OPEN | - ZFCP_STATUS_COMMON_OPEN), &port->status) - == (ZFCP_STATUS_PORT_PHYS_OPEN | ZFCP_STATUS_COMMON_OPEN)) { + ZFCP_STATUS_COMMON_OPEN), + &port->status)) { ZFCP_LOG_DEBUG("Port wwpn=0x%Lx is open -> trying " " close physical\n", port->wwpn); @@ -2433,8 +2494,7 @@ zfcp_erp_port_strategy_open(struct zfcp_ int retval; if (atomic_test_mask(ZFCP_STATUS_PORT_NAMESERVER, - &erp_action->port->status) - == ZFCP_STATUS_PORT_NAMESERVER) + &erp_action->port->status)) retval = zfcp_erp_port_strategy_open_nameserver(erp_action); else retval = zfcp_erp_port_strategy_open_common(erp_action); @@ -3041,6 +3101,12 @@ zfcp_erp_action_enqueue(int action, goto out; } if (!atomic_test_mask + (ZFCP_STATUS_COMMON_RUNNING, &port->status) || + atomic_test_mask + (ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) { + goto out; + } + if (!atomic_test_mask (ZFCP_STATUS_COMMON_UNBLOCKED, &port->status)) { stronger_action = ZFCP_ERP_ACTION_REOPEN_PORT; unit = NULL; @@ -3068,6 +3134,12 @@ zfcp_erp_action_enqueue(int action, goto out; } if (!atomic_test_mask + (ZFCP_STATUS_COMMON_RUNNING, &adapter->status) || + atomic_test_mask + (ZFCP_STATUS_COMMON_ERP_FAILED, &adapter->status)) { + goto out; + } + if (!atomic_test_mask (ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status)) { stronger_action = ZFCP_ERP_ACTION_REOPEN_ADAPTER; port = NULL; @@ -3178,18 +3250,15 @@ zfcp_erp_action_dequeue(struct zfcp_erp_ case ZFCP_ERP_ACTION_REOPEN_UNIT: atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &erp_action->unit->status); - zfcp_unit_put(erp_action->unit); break; case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: case ZFCP_ERP_ACTION_REOPEN_PORT: atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &erp_action->port->status); - zfcp_port_put(erp_action->port); break; case ZFCP_ERP_ACTION_REOPEN_ADAPTER: atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &erp_action->adapter->status); - zfcp_adapter_put(adapter); break; default: /* bug */ @@ -3198,6 +3267,39 @@ zfcp_erp_action_dequeue(struct zfcp_erp_ return retval; } +/** + * zfcp_erp_action_cleanup + * + * registers unit with scsi stack if appropiate and fixes reference counts + */ + +static void +zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter, + struct zfcp_port *port, struct zfcp_unit *unit, + int result) +{ + if ((action == ZFCP_ERP_ACTION_REOPEN_UNIT) + && (result == ZFCP_ERP_SUCCEEDED) + && (!unit->device)) { + zfcp_erp_schedule_work(unit); + } + switch (action) { + case ZFCP_ERP_ACTION_REOPEN_UNIT: + zfcp_unit_put(unit); + break; + case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: + case ZFCP_ERP_ACTION_REOPEN_PORT: + zfcp_port_put(port); + break; + case ZFCP_ERP_ACTION_REOPEN_ADAPTER: + zfcp_adapter_put(adapter); + break; + default: + break; + } +} + + /* * function: * diff -puN drivers/s390/scsi/zfcp_ext.h~s390-07-zfcp-host-adapter drivers/s390/scsi/zfcp_ext.h --- 25/drivers/s390/scsi/zfcp_ext.h~s390-07-zfcp-host-adapter Thu Jan 8 14:11:34 2004 +++ 25-akpm/drivers/s390/scsi/zfcp_ext.h Thu Jan 8 14:11:34 2004 @@ -30,9 +30,7 @@ #ifndef ZFCP_EXT_H #define ZFCP_EXT_H /* this drivers version (do not edit !!! generated and updated by cvs) */ -#define ZFCP_EXT_REVISION "$Revision: 1.33 $" - -#ifdef __KERNEL__ +#define ZFCP_EXT_REVISION "$Revision: 1.38 $" #include "zfcp_def.h" @@ -44,7 +42,9 @@ extern void zfcp_sysfs_driver_remove_fil extern int zfcp_sysfs_adapter_create_files(struct device *); extern void zfcp_sysfs_adapter_remove_files(struct device *); extern int zfcp_sysfs_port_create_files(struct device *, u32); +extern void zfcp_sysfs_port_remove_files(struct device *, u32); extern int zfcp_sysfs_unit_create_files(struct device *); +extern void zfcp_sysfs_unit_remove_files(struct device *); extern void zfcp_sysfs_port_release(struct device *); extern int zfcp_sysfs_port_shutdown(struct zfcp_port *); extern void zfcp_sysfs_unit_release(struct device *); @@ -112,9 +112,6 @@ extern void zfcp_fsf_els_processing(stru extern int zfcp_adapter_scsi_register(struct zfcp_adapter *); extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *); extern void zfcp_scsi_block_requests(struct Scsi_Host *); -extern void zfcp_scsi_insert_into_fake_queue(struct zfcp_adapter *, - Scsi_Cmnd *); -extern void zfcp_scsi_process_and_clear_fake_queue(unsigned long); extern int zfcp_create_sbals_from_sg(struct zfcp_fsf_req *, Scsi_Cmnd *, char, int, int); extern void zfcp_set_fcp_dl(struct fcp_cmnd_iu *, fcp_dl_t); @@ -159,5 +156,4 @@ extern void zfcp_in_els_dbf_event(struct #ifdef ZFCP_STAT_REQSIZES extern int zfcp_statistics_inc(struct list_head *, u32); #endif -#endif /* __KERNEL__ */ #endif /* ZFCP_EXT_H */ diff -puN drivers/s390/scsi/zfcp_fsf.c~s390-07-zfcp-host-adapter drivers/s390/scsi/zfcp_fsf.c --- 25/drivers/s390/scsi/zfcp_fsf.c~s390-07-zfcp-host-adapter Thu Jan 8 14:11:34 2004 +++ 25-akpm/drivers/s390/scsi/zfcp_fsf.c Thu Jan 8 14:11:34 2004 @@ -28,7 +28,7 @@ */ /* this drivers version (do not edit !!! generated and updated by cvs) */ -#define ZFCP_FSF_C_REVISION "$Revision: 1.12 $" +#define ZFCP_FSF_C_REVISION "$Revision: 1.16 $" #include "zfcp_ext.h" @@ -101,7 +101,8 @@ zfcp_fsf_req_alloc(struct zfcp_adapter * case FSF_QTCB_ABORT_FCP_CMND: fsf_req = zfcp_fsf_req_get(kmalloc_flags, adapter->pool.fcp_command_fsf); - if (fsf_req && (fsf_req->status & ZFCP_STATUS_FSFREQ_POOL)) { + if (unlikely(fsf_req && + (fsf_req->status & ZFCP_STATUS_FSFREQ_POOL))) { /* * watch low mem buffer * Note: If the command is reset or aborted, two @@ -116,7 +117,8 @@ zfcp_fsf_req_alloc(struct zfcp_adapter * } #ifdef ZFCP_DEBUG_REQUESTS debug_text_event(adapter->req_dbf, 5, "fsfa_fcp"); - if (fsf_req && (fsf_req->status & ZFCP_STATUS_FSFREQ_POOL)) + if (unlikely(fsf_req && + (fsf_req->status & ZFCP_STATUS_FSFREQ_POOL))) debug_text_event(adapter->req_dbf, 5, "fsfa_pl"); #endif /* ZFCP_DEBUG_REQUESTS */ break; @@ -158,7 +160,7 @@ zfcp_fsf_req_alloc(struct zfcp_adapter * "(debug info 0x%x)\n", fsf_cmd); } //switch(fsf_cmd) - if (!fsf_req) { + if (unlikely(!fsf_req)) { ZFCP_LOG_DEBUG("error: Out of memory. Allocation of FSF " "request structure failed\n"); } else { @@ -171,7 +173,7 @@ zfcp_fsf_req_alloc(struct zfcp_adapter * #ifdef ZFCP_DEBUG_REQUESTS debug_event(adapter->req_dbf, 5, &fsf_req, sizeof (unsigned long)); - if (fsf_req->qtcb) + if (likely(fsf_req->qtcb)) debug_event(adapter->req_dbf, 5, &fsf_req->qtcb, sizeof (unsigned long)); #endif /* ZFCP_DEBUG_REQUESTS */ @@ -198,7 +200,7 @@ zfcp_fsf_req_free(struct zfcp_fsf_req *f case FSF_QTCB_FCP_CMND: case FSF_QTCB_ABORT_FCP_CMND: - if (fsf_req->status & ZFCP_STATUS_FSFREQ_POOL) { + if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_POOL)) { del_timer(&adapter->pool.fcp_command_fsf_timer); mempool_free(fsf_req, adapter->pool.fcp_command_fsf); } else @@ -299,7 +301,7 @@ zfcp_fsf_req_complete(struct zfcp_fsf_re /* do some statistics */ atomic_dec(&adapter->fsf_reqs_active); - if (fsf_req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS) { + if (unlikely(fsf_req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS)) { ZFCP_LOG_DEBUG("Status read response received\n"); /* * Note: all cleanup handling is done in the callchain of @@ -314,7 +316,7 @@ zfcp_fsf_req_complete(struct zfcp_fsf_re * fsf_req may be deleted due to waking up functions, so * cleanup is saved here and used later */ - if (fsf_req->status & ZFCP_STATUS_FSFREQ_CLEANUP) + if (likely(fsf_req->status & ZFCP_STATUS_FSFREQ_CLEANUP)) cleanup = 1; else cleanup = 0; @@ -322,7 +324,7 @@ zfcp_fsf_req_complete(struct zfcp_fsf_re fsf_req->status |= ZFCP_STATUS_FSFREQ_COMPLETED; /* cleanup request if requested by initiator */ - if (cleanup) { + if (likely(cleanup)) { ZFCP_LOG_TRACE("removing FSF request 0x%lx\n", (unsigned long) fsf_req); /* @@ -334,6 +336,16 @@ zfcp_fsf_req_complete(struct zfcp_fsf_re /* notify initiator waiting for the requests completion */ ZFCP_LOG_TRACE("waking initiator of FSF request 0x%lx\n", (unsigned long) fsf_req); + /* + * FIXME: Race! We must not access fsf_req here as it might have been + * cleaned up already due to the set ZFCP_STATUS_FSFREQ_COMPLETED + * flag. It's an improbable case. But, we have the same paranoia for + * the cleanup flag already. + * Might better be handled using complete()? + * (setting the flag and doing wakeup ought to be atomic + * with regard to checking the flag as long as waitqueue is + * part of the to be released structure) + */ wake_up(&fsf_req->completion_wq); } @@ -372,7 +384,7 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf } /* log additional information provided by FSF (if any) */ - if (fsf_req->qtcb->header.log_length) { + if (unlikely(fsf_req->qtcb->header.log_length)) { /* do not trust them ;-) */ if (fsf_req->qtcb->header.log_start > ZFCP_QTCB_SIZE) { ZFCP_LOG_NORMAL @@ -686,7 +698,7 @@ zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_ { int retval = 0; - if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { + if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) { goto skip_fsfstatus; } @@ -835,7 +847,7 @@ zfcp_fsf_req_dispatch(struct zfcp_fsf_re { int retval = 0; - if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { + if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) { ZFCP_LOG_TRACE("fsf_req=0x%lx, QTCB=0x%lx\n", (unsigned long) fsf_req, (unsigned long) (fsf_req->qtcb)); @@ -1996,6 +2008,20 @@ zfcp_fsf_open_port_handler(struct zfcp_f ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); retval = 0; /* check whether D_ID has changed during open */ + /* + * FIXME: This check is not airtight, as the FCP channel does + * not monitor closures of target port connections caused on + * the remote side. Thus, they might miss out on invalidating + * locally cached WWPNs (and other N_Port parameters) of gone + * target ports. So, our heroic attempt to make things safe + * could be undermined by 'open port' response data tagged with + * obsolete WWPNs. Another reason to monitor potential + * connection closures ourself at least (by interpreting + * incoming ELS' and unsolicited status). It just crosses my + * mind that one should be able to cross-check by means of + * another GID_PN straight after a port has been opened. + * Alternately, an ADISC/PDISC ELS should suffice, as well. + */ plogi = (struct fsf_plogi *) fsf_req->qtcb->bottom.support.els; if (!atomic_test_mask(ZFCP_STATUS_PORT_NO_WWPN, &port->status)) { @@ -2398,9 +2424,9 @@ zfcp_fsf_open_unit(struct zfcp_erp_actio } erp_action->fsf_req->qtcb->header.port_handle = - erp_action->port->handle; - *(fcp_lun_t *) & (erp_action->fsf_req->qtcb->bottom.support.fcp_lun) - = erp_action->unit->fcp_lun; + erp_action->port->handle; + erp_action->fsf_req->qtcb->bottom.support.fcp_lun = + erp_action->unit->fcp_lun; atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->unit->status); erp_action->fsf_req->data.open_unit.unit = erp_action->unit; erp_action->fsf_req->erp_action = erp_action; @@ -2835,7 +2861,7 @@ zfcp_fsf_send_fcp_command_task(struct zf retval = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, &lock_flags, req_flags, &(fsf_req)); - if (retval < 0) { + if (unlikely(retval < 0)) { ZFCP_LOG_DEBUG("error: Out of resources. Could not create an " "FCP command request for FCP-LUN 0x%Lx " "connected to the port with WWPN 0x%Lx " @@ -2928,7 +2954,7 @@ zfcp_fsf_send_fcp_command_task(struct zf fcp_cmnd_iu->fcp_lun = unit->fcp_lun; /* set task attributes in FCP_CMND IU in QTCB */ - if (scsi_cmnd->device->simple_tags) { + if (likely(scsi_cmnd->device->simple_tags)) { fcp_cmnd_iu->task_attribute = SIMPLE_Q; ZFCP_LOG_TRACE("setting SIMPLE_Q task attribute\n"); } else { @@ -2937,7 +2963,7 @@ zfcp_fsf_send_fcp_command_task(struct zf } /* set additional length of FCP_CDB in FCP_CMND IU in QTCB, if needed */ - if (scsi_cmnd->cmd_len > FCP_CDB_LENGTH) { + if (unlikely(scsi_cmnd->cmd_len > FCP_CDB_LENGTH)) { fcp_cmnd_iu->add_fcp_cdb_length = (scsi_cmnd->cmd_len - FCP_CDB_LENGTH) >> 2; ZFCP_LOG_TRACE("SCSI CDB length is 0x%x, " @@ -2965,9 +2991,9 @@ zfcp_fsf_send_fcp_command_task(struct zf /* Note: >= and not = because the combined scatter-gather entries * may be larger than request_bufflen according to the mailing list */ - if (real_bytes >= scsi_cmnd->request_bufflen) { + if (likely(real_bytes >= scsi_cmnd->request_bufflen)) { ZFCP_LOG_TRACE("Data fits\n"); - } else if (real_bytes == 0) { + } else if (likely(real_bytes == 0)) { ZFCP_LOG_DEBUG("Data did not fit into available buffer(s), " "waiting for more...\n"); retval = -EIO; @@ -2996,7 +3022,7 @@ zfcp_fsf_send_fcp_command_task(struct zf * covered by an SBALE) */ retval = zfcp_fsf_req_send(fsf_req, NULL); - if (retval < 0) { + if (unlikely(retval < 0)) { ZFCP_LOG_INFO("error: Could not send an FCP command request " "for a command on the adapter %s, " "port WWPN 0x%Lx and unit LUN 0x%Lx\n", @@ -3139,12 +3165,12 @@ zfcp_fsf_send_fcp_command_handler(struct int retval = -EINVAL; struct zfcp_unit *unit; - if (fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT) + if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)) unit = fsf_req->data.send_fcp_command_task_management.unit; else unit = fsf_req->data.send_fcp_command_task.unit; - if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { + if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) { /* go directly to calls of special handlers */ goto skip_fsfstatus; } @@ -3445,7 +3471,6 @@ static int zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) { int retval = 0; - struct zfcp_adapter *adapter = fsf_req->adapter; Scsi_Cmnd *scpnt; struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *) @@ -3459,14 +3484,14 @@ zfcp_fsf_send_fcp_command_task_handler(s read_lock_irqsave(&fsf_req->adapter->abort_lock, flags); scpnt = fsf_req->data.send_fcp_command_task.scsi_cmnd; - if (!scpnt) { + if (unlikely(!scpnt)) { ZFCP_LOG_DEBUG ("Command with fsf_req 0x%lx is not associated to " "a scsi command anymore. Aborted?\n", (unsigned long) fsf_req); goto out; } - if (fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTED) { + if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTED)) { /* FIXME: (design) mid-layer should handle DID_ABORT like * DID_SOFT_ERROR by retrying the request for devices * that allow retries. @@ -3477,7 +3502,7 @@ zfcp_fsf_send_fcp_command_task_handler(s goto skip_fsfstatus; } - if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { + if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) { ZFCP_LOG_DEBUG("Setting DID_ERROR\n"); set_host_byte(&scpnt->result, DID_ERROR); goto skip_fsfstatus; @@ -3491,7 +3516,7 @@ zfcp_fsf_send_fcp_command_task_handler(s * of result in SCSI command */ scpnt->result |= fcp_rsp_iu->scsi_status; - if (fcp_rsp_iu->scsi_status) { + if (unlikely(fcp_rsp_iu->scsi_status)) { /* DEBUG */ ZFCP_LOG_NORMAL("status for SCSI Command:\n"); ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL, @@ -3507,7 +3532,7 @@ zfcp_fsf_send_fcp_command_task_handler(s } /* check FCP_RSP_INFO */ - if (fcp_rsp_iu->validity.bits.fcp_rsp_len_valid) { + if (unlikely(fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)) { ZFCP_LOG_DEBUG("rsp_len is valid\n"); switch (fcp_rsp_info[3]) { case RSP_CODE_GOOD: @@ -3600,7 +3625,7 @@ zfcp_fsf_send_fcp_command_task_handler(s } /* check for sense data */ - if (fcp_rsp_iu->validity.bits.fcp_sns_len_valid) { + if (unlikely(fcp_rsp_iu->validity.bits.fcp_sns_len_valid)) { sns_len = FSF_FCP_RSP_SIZE - sizeof (struct fcp_rsp_iu) + fcp_rsp_iu->fcp_rsp_len; ZFCP_LOG_TRACE("room for %i bytes sense data in QTCB\n", @@ -3623,7 +3648,7 @@ zfcp_fsf_send_fcp_command_task_handler(s } /* check for overrun */ - if (fcp_rsp_iu->validity.bits.fcp_resid_over) { + if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_over)) { ZFCP_LOG_INFO("A data overrun was detected for a command. " "This happened for a command to the unit " "with FCP LUN 0x%Lx connected to the " @@ -3638,7 +3663,7 @@ zfcp_fsf_send_fcp_command_task_handler(s } /* check for underrun */ - if (fcp_rsp_iu->validity.bits.fcp_resid_under) { + if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_under)) { ZFCP_LOG_DEBUG("A data underrun was detected for a command. " "This happened for a command to the unit " "with FCP LUN 0x%Lx connected to the " @@ -3755,9 +3780,6 @@ zfcp_fsf_send_fcp_command_task_handler(s * the new eh */ /* always call back */ - (scpnt->scsi_done) (scpnt); - atomic_dec(&adapter->scsi_reqs_active); - wake_up(&adapter->scsi_reqs_active_wq); #ifdef ZFCP_DEBUG_REQUESTS debug_text_event(fsf_req->adapter->req_dbf, 2, "ok_done:"); debug_event(fsf_req->adapter->req_dbf, 2, &scpnt, @@ -3768,8 +3790,6 @@ zfcp_fsf_send_fcp_command_task_handler(s sizeof (unsigned long)); #endif /* ZFCP_DEBUG_REQUESTS */ (scpnt->scsi_done) (scpnt); - atomic_dec(&adapter->scsi_reqs_active); - wake_up(&adapter->scsi_reqs_active_wq); /* * We must hold this lock until scsi_done has been called. * Otherwise we may call scsi_done after abort regarding this @@ -3904,7 +3924,7 @@ zfcp_fsf_req_create_sbal_check(unsigned struct zfcp_qdio_queue *queue, int needed) { write_lock_irqsave(&queue->queue_lock, *flags); - if (atomic_read(&queue->free_count) >= needed) + if (likely(atomic_read(&queue->free_count) >= needed)) return 1; write_unlock_irqrestore(&queue->queue_lock, *flags); return 0; @@ -3942,7 +3962,7 @@ zfcp_fsf_req_create(struct zfcp_adapter /* allocate new FSF request */ fsf_req = zfcp_fsf_req_alloc(adapter, fsf_cmd, GFP_ATOMIC); - if (!fsf_req) { + if (unlikely(!fsf_req)) { ZFCP_LOG_DEBUG("error: Could not put an FSF request into" "the outbound (send) queue.\n"); retval = -ENOMEM; @@ -3960,11 +3980,11 @@ zfcp_fsf_req_create(struct zfcp_adapter fsf_req->specific_magic = ZFCP_MAGIC_FSFREQ; fsf_req->fsf_command = fsf_cmd; - if (req_flags & ZFCP_REQ_AUTO_CLEANUP) + if (likely(req_flags & ZFCP_REQ_AUTO_CLEANUP)) fsf_req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; /* initialize QTCB */ - if (fsf_cmd != FSF_QTCB_UNSOLICITED_STATUS) { + if (likely(fsf_cmd != FSF_QTCB_UNSOLICITED_STATUS)) { ZFCP_LOG_TRACE("fsf_req->qtcb=0x%lx\n", (unsigned long) fsf_req->qtcb); fsf_req->qtcb->prefix.req_id = (unsigned long) fsf_req; @@ -3983,7 +4003,7 @@ zfcp_fsf_req_create(struct zfcp_adapter * try to get needed SBALs in request queue (get queue lock on success) */ ZFCP_LOG_TRACE("try to get free BUFFER in request queue\n"); - if (req_flags & ZFCP_WAIT_FOR_SBAL) { + if (unlikely(req_flags & ZFCP_WAIT_FOR_SBAL)) { timeout = ZFCP_SBAL_TIMEOUT; ZFCP_WAIT_EVENT_TIMEOUT(adapter->request_wq, timeout, @@ -4009,7 +4029,7 @@ zfcp_fsf_req_create(struct zfcp_adapter /* setup common SBALE fields */ buffere[0].addr = fsf_req; buffere[0].flags |= SBAL_FLAGS0_COMMAND; - if (fsf_cmd != FSF_QTCB_UNSOLICITED_STATUS) { + if (likely(fsf_cmd != FSF_QTCB_UNSOLICITED_STATUS)) { buffere[1].addr = (void *) fsf_req->qtcb; buffere[1].length = ZFCP_QTCB_SIZE; } @@ -4116,7 +4136,7 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *f buffere->length); /* set sequence counter in QTCB */ - if (fsf_req->qtcb) { + if (likely(fsf_req->qtcb)) { fsf_req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no; fsf_req->seq_no = adapter->fsf_req_seq_no; ZFCP_LOG_TRACE("FSF request 0x%lx of adapter 0x%lx gets " @@ -4133,7 +4153,7 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *f write_unlock_irqrestore(&adapter->fsf_req_list_lock, flags); /* figure out expiration time of timeout and start timeout */ - if (timer) { + if (unlikely(timer)) { timer->expires += jiffies; add_timer(timer); } @@ -4167,7 +4187,7 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *f QDIO_FLAG_SYNC_OUTPUT, 0, fsf_req->sbal_index, fsf_req->sbal_count, NULL); - if (retval) { + if (unlikely(retval)) { /* Queues are down..... */ retval = -EIO; /* @@ -4198,7 +4218,7 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *f debug_text_event(adapter->req_dbf, 1, "o:a/seq"); debug_event(adapter->req_dbf, 1, &fsf_req, sizeof (unsigned long)); - if (inc_seq_no) { + if (likely(inc_seq_no)) { debug_event(adapter->req_dbf, 1, &adapter->fsf_req_seq_no, sizeof (u32)); } else { @@ -4213,7 +4233,7 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *f * otherwise, */ /* Don't increase for unsolicited status */ - if (inc_seq_no) { + if (likely(inc_seq_no)) { adapter->fsf_req_seq_no++; ZFCP_LOG_TRACE ("FSF sequence counter value of adapter 0x%lx " @@ -4263,16 +4283,16 @@ zfcp_fsf_req_get(int kmalloc_flags, memp struct zfcp_fsf_req *fsf_req; fsf_req = kmalloc(ZFCP_QTCB_AND_REQ_SIZE, kmalloc_flags); - if (fsf_req) { + if (likely(fsf_req)) { memset(fsf_req, 0, ZFCP_QTCB_AND_REQ_SIZE); } else { fsf_req = mempool_alloc(pool, kmalloc_flags); - if (fsf_req) { + if (likely(fsf_req)) { memset(fsf_req, 0, ZFCP_QTCB_AND_REQ_SIZE); fsf_req->status |= ZFCP_STATUS_FSFREQ_POOL; } } - if (fsf_req) + if (likely(fsf_req)) fsf_req->qtcb = (struct fsf_qtcb *) ((unsigned long) fsf_req + sizeof (struct zfcp_fsf_req)); diff -puN drivers/s390/scsi/zfcp_fsf.h~s390-07-zfcp-host-adapter drivers/s390/scsi/zfcp_fsf.h --- 25/drivers/s390/scsi/zfcp_fsf.h~s390-07-zfcp-host-adapter Thu Jan 8 14:11:34 2004 +++ 25-akpm/drivers/s390/scsi/zfcp_fsf.h Thu Jan 8 14:11:34 2004 @@ -30,8 +30,6 @@ #ifndef FSF_H #define FSF_H -#ifdef __KERNEL__ - #define FSF_QTCB_VERSION1 0x00000001 #define FSF_QTCB_CURRENT_VERSION FSF_QTCB_VERSION1 @@ -354,5 +352,4 @@ struct fsf_qtcb { union fsf_qtcb_bottom bottom; } __attribute__ ((packed)); -#endif /* __KERNEL__ */ #endif /* FSF_H */ diff -puN drivers/s390/scsi/zfcp_qdio.c~s390-07-zfcp-host-adapter drivers/s390/scsi/zfcp_qdio.c --- 25/drivers/s390/scsi/zfcp_qdio.c~s390-07-zfcp-host-adapter Thu Jan 8 14:11:34 2004 +++ 25-akpm/drivers/s390/scsi/zfcp_qdio.c Thu Jan 8 14:11:34 2004 @@ -27,7 +27,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#define ZFCP_QDIO_C_REVISION "$Revision: 1.7 $" +#define ZFCP_QDIO_C_REVISION "$Revision: 1.10 $" #include "zfcp_ext.h" @@ -214,7 +214,7 @@ zfcp_qdio_handler_error_check(struct zfc " QDIO_STATUS_OUTBOUND_INT \n"); } } // if (ZFCP_LOG_CHECK(ZFCP_LOG_LEVEL_TRACE)) - if (status & QDIO_STATUS_LOOK_FOR_ERROR) { + if (unlikely(status & QDIO_STATUS_LOOK_FOR_ERROR)) { retval = -EIO; ZFCP_LOG_FLAGS(1, "QDIO_STATUS_LOOK_FOR_ERROR \n"); @@ -261,7 +261,17 @@ zfcp_qdio_handler_error_check(struct zfc } /* Restarting IO on the failed adapter from scratch */ debug_text_event(adapter->erp_dbf, 1, "qdio_err"); - zfcp_erp_adapter_reopen(adapter, 0); + /* + * Since we have been using this adapter, it is save to assume + * that it is not failed but recoverable. The card seems to + * report link-up events by self-initiated queue shutdown. + * That is why we need to clear the the link-down flag + * which is set again in case we have missed by a mile. + */ + zfcp_erp_adapter_reopen( + adapter, + ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | + ZFCP_STATUS_COMMON_ERP_FAILED); } return retval; } @@ -293,8 +303,8 @@ zfcp_qdio_request_handler(struct ccw_dev zfcp_get_busid_by_adapter(adapter), first_element, elements_processed); - if (zfcp_qdio_handler_error_check(adapter, status, qdio_error, - siga_error)) + if (unlikely(zfcp_qdio_handler_error_check(adapter, status, qdio_error, + siga_error))) goto out; /* * we stored address of struct zfcp_adapter data structure @@ -345,8 +355,8 @@ zfcp_qdio_response_handler(struct ccw_de adapter = (struct zfcp_adapter *) int_parm; queue = &adapter->response_queue; - if (zfcp_qdio_handler_error_check(adapter, status, qdio_error, - siga_error)) + if (unlikely(zfcp_qdio_handler_error_check(adapter, status, qdio_error, + siga_error))) goto out; /* @@ -394,11 +404,17 @@ zfcp_qdio_response_handler(struct ccw_de ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL, (char *) buffer, SBAL_SIZE); } - if (buffere->flags & SBAL_FLAGS_LAST_ENTRY) + /* + * A single used SBALE per inbound SBALE has been + * implemented by QDIO so far. Hope they will + * do some optimisation. Will need to change to + * unlikely() then. + */ + if (likely(buffere->flags & SBAL_FLAGS_LAST_ENTRY)) break; }; - if (!buffere->flags & SBAL_FLAGS_LAST_ENTRY) { + if (unlikely(!(buffere->flags & SBAL_FLAGS_LAST_ENTRY))) { ZFCP_LOG_NORMAL("bug: End of inbound data " "not marked!\n"); } @@ -421,7 +437,7 @@ zfcp_qdio_response_handler(struct ccw_de QDIO_FLAG_SYNC_INPUT | QDIO_FLAG_UNDER_INTERRUPT, 0, start, count, NULL); - if (retval) { + if (unlikely(retval)) { atomic_set(&queue->free_count, count); ZFCP_LOG_DEBUG("Inbound data regions could not be cleared " "Transfer queues may be down. " @@ -458,7 +474,7 @@ zfcp_qdio_reqid_check(struct zfcp_adapte #endif /* ZFCP_DEBUG_REQUESTS */ /* invalid (per convention used in this driver) */ - if (!sbale_addr) { + if (unlikely(!sbale_addr)) { ZFCP_LOG_NORMAL ("bug: Inbound data faulty, contains null-pointer!\n"); retval = -EINVAL; @@ -468,8 +484,8 @@ zfcp_qdio_reqid_check(struct zfcp_adapte /* valid request id and thus (hopefully :) valid fsf_req address */ fsf_req = (struct zfcp_fsf_req *) sbale_addr; - if ((fsf_req->common_magic != ZFCP_MAGIC) || - (fsf_req->specific_magic != ZFCP_MAGIC_FSFREQ)) { + if (unlikely((fsf_req->common_magic != ZFCP_MAGIC) || + (fsf_req->specific_magic != ZFCP_MAGIC_FSFREQ))) { ZFCP_LOG_NORMAL("bug: An inbound FSF acknowledgement was " "faulty (debug info 0x%x, 0x%x, 0x%lx)\n", fsf_req->common_magic, @@ -479,7 +495,7 @@ zfcp_qdio_reqid_check(struct zfcp_adapte goto out; } - if (adapter != fsf_req->adapter) { + if (unlikely(adapter != fsf_req->adapter)) { ZFCP_LOG_NORMAL("bug: An inbound FSF acknowledgement was not " "correct (debug info 0x%lx, 0x%lx, 0%lx) \n", (unsigned long) fsf_req, @@ -490,7 +506,7 @@ zfcp_qdio_reqid_check(struct zfcp_adapte } #ifdef ZFCP_DEBUG_REQUESTS /* debug feature stuff (test for QTCB: remember new unsol. status!) */ - if (fsf_req->qtcb) { + if (likely(fsf_req->qtcb)) { debug_event(adapter->req_dbf, 1, &fsf_req->qtcb->prefix.req_seq_no, sizeof (u32)); } @@ -498,7 +514,7 @@ zfcp_qdio_reqid_check(struct zfcp_adapte ZFCP_LOG_TRACE("fsf_req at 0x%lx, QTCB at 0x%lx\n", (unsigned long) fsf_req, (unsigned long) fsf_req->qtcb); - if (fsf_req->qtcb) { + if (likely(fsf_req->qtcb)) { ZFCP_LOG_TRACE("HEX DUMP OF 1ST BUFFERE PAYLOAD (QTCB):\n"); ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, (char *) fsf_req->qtcb, ZFCP_QTCB_SIZE); @@ -518,8 +534,8 @@ zfcp_qdio_determine_pci(struct zfcp_qdio int pci_pos; new_distance_from_int = req_queue->distance_from_int + - fsf_req->sbal_count; - if (new_distance_from_int >= ZFCP_QDIO_PCI_INTERVAL) { + fsf_req->sbal_count; + if (unlikely(new_distance_from_int >= ZFCP_QDIO_PCI_INTERVAL)) { new_distance_from_int %= ZFCP_QDIO_PCI_INTERVAL; pci_pos = fsf_req->sbal_index; pci_pos += fsf_req->sbal_count; diff -puN drivers/s390/scsi/zfcp_scsi.c~s390-07-zfcp-host-adapter drivers/s390/scsi/zfcp_scsi.c --- 25/drivers/s390/scsi/zfcp_scsi.c~s390-07-zfcp-host-adapter Thu Jan 8 14:11:34 2004 +++ 25-akpm/drivers/s390/scsi/zfcp_scsi.c Thu Jan 8 14:11:34 2004 @@ -30,7 +30,7 @@ #define ZFCP_LOG_AREA ZFCP_LOG_AREA_SCSI #define ZFCP_LOG_AREA_PREFIX ZFCP_LOG_AREA_PREFIX_SCSI /* this drivers version (do not edit !!! generated and updated by cvs) */ -#define ZFCP_SCSI_REVISION "$Revision: 1.38 $" +#define ZFCP_SCSI_REVISION "$Revision: 1.42 $" #include @@ -225,99 +225,6 @@ zfcp_scsi_slave_destroy(struct scsi_devi } } -/* - * function: zfcp_scsi_insert_into_fake_queue - * - * purpose: - * - * - * returns: - * - * FIXME: Is the following scenario possible and - even more interesting - - * a problem? It reminds me of the famous 'no retry for tape' fix - * (no problem for disks, but what is about tapes...) - * - * device is unaccessable, - * command A is put into the fake queue, - * device becomes accessable again, - * command B is queued to the device, - * fake queue timer expires - * command A is returned to the mid-layer - * command A is queued to the device - */ -void -zfcp_scsi_insert_into_fake_queue(struct zfcp_adapter *adapter, - Scsi_Cmnd * new_cmnd) -{ - unsigned long flags; - Scsi_Cmnd *current_cmnd; - - ZFCP_LOG_DEBUG("Faking SCSI command:\n"); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, - (char *) new_cmnd->cmnd, new_cmnd->cmd_len); - - new_cmnd->host_scribble = NULL; - - write_lock_irqsave(&adapter->fake_list_lock, flags); - if (adapter->first_fake_cmnd == NULL) { - adapter->first_fake_cmnd = new_cmnd; - adapter->fake_scsi_timer.function = - zfcp_scsi_process_and_clear_fake_queue; - adapter->fake_scsi_timer.data = (unsigned long) adapter; - adapter->fake_scsi_timer.expires = - jiffies + ZFCP_FAKE_SCSI_COMPLETION_TIME; - add_timer(&adapter->fake_scsi_timer); - } else { - for (current_cmnd = adapter->first_fake_cmnd; - current_cmnd->host_scribble != NULL; - current_cmnd = - (Scsi_Cmnd *) (current_cmnd->host_scribble)) ; - current_cmnd->host_scribble = (char *) new_cmnd; - } - write_unlock_irqrestore(&adapter->fake_list_lock, flags); -} - -/* - * function: zfcp_scsi_process_and_clear_fake_queue - * - * purpose: - * - * - * returns: - */ -void -zfcp_scsi_process_and_clear_fake_queue(unsigned long data) -{ - unsigned long flags; - struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; - Scsi_Cmnd *cur = adapter->first_fake_cmnd; - Scsi_Cmnd *next; - - /* - * We need a common lock for scsi_req on command completion - * as well as on command abort to avoid race conditions - * during completions and aborts taking place at the same time. - * It needs to be the outer lock as in the eh_abort_handler. - */ - read_lock_irqsave(&adapter->abort_lock, flags); - write_lock(&adapter->fake_list_lock); - while (cur) { - next = (Scsi_Cmnd *) cur->host_scribble; - cur->host_scribble = NULL; - zfcp_cmd_dbf_event_scsi("clrfake", cur); - cur->scsi_done(cur); - cur = next; -#ifdef ZFCP_DEBUG_REQUESTS - debug_text_event(adapter->req_dbf, 2, "fk_done:"); - debug_event(adapter->req_dbf, 2, &cur, sizeof (unsigned long)); -#endif - } - adapter->first_fake_cmnd = NULL; - write_unlock(&adapter->fake_list_lock); - read_unlock_irqrestore(&adapter->abort_lock, flags); - return; -} - void zfcp_scsi_block_requests(struct Scsi_Host *shpnt) { @@ -383,25 +290,6 @@ zfcp_scsi_slave_configure(struct scsi_de return 0; } -/* Sends command on a round-trip using SCSI stack */ -static void -zfcp_scsi_queuecommand_fake(Scsi_Cmnd * scpnt, struct zfcp_adapter *adapter) -{ - ZFCP_LOG_DEBUG("Looping SCSI IO on the adapter %s.\n", - zfcp_get_busid_by_adapter(adapter)); - /* - * Reset everything for devices with retries, allow at least one retry - * for others, e.g. tape. - */ - scpnt->retries = 0; - if (scpnt->allowed == 1) { - scpnt->allowed = 2; - } - set_host_byte(&scpnt->result, DID_SOFT_ERROR); - set_driver_byte(&scpnt->result, SUGGEST_RETRY); - zfcp_scsi_insert_into_fake_queue(adapter, scpnt); -} - /* Complete a command immediately handing back DID_ERROR */ static void zfcp_scsi_queuecommand_stop(Scsi_Cmnd * scpnt, @@ -460,10 +348,12 @@ zfcp_scsi_queuecommand_stop(Scsi_Cmnd * int zfcp_scsi_queuecommand(Scsi_Cmnd * scpnt, void (*done) (Scsi_Cmnd *)) { + int retval; int temp_ret; struct zfcp_unit *unit; struct zfcp_adapter *adapter; + retval = 0; /* reset the status for this request */ scpnt->result = 0; /* save address of mid layer call back function */ @@ -475,47 +365,38 @@ zfcp_scsi_queuecommand(Scsi_Cmnd * scpnt */ adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0]; /* NULL when the adapter was removed from the zfcp list */ - if (adapter == NULL) { + if (unlikely(adapter == NULL)) { zfcp_scsi_queuecommand_stop(scpnt, NULL, NULL); goto out; } - /* set when we have a unit/port list modification */ - if (atomic_test_mask(ZFCP_STATUS_ADAPTER_QUEUECOMMAND_BLOCK, - &adapter->status)) { - zfcp_scsi_queuecommand_fake(scpnt, adapter); - goto out; - } - unit = zfcp_scsi_determine_unit(adapter, scpnt); - if (unit == NULL) + if (unlikely(unit == NULL)) goto out; - if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status) - || !atomic_test_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status)) { + if (unlikely( + atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status) || + !atomic_test_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status))) { zfcp_scsi_queuecommand_stop(scpnt, adapter, unit); goto out; } - if (!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status)) { + if (unlikely( + !atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status))) { ZFCP_LOG_DEBUG("adapter %s not ready or unit with LUN 0x%Lx " "on the port with WWPN 0x%Lx in recovery.\n", zfcp_get_busid_by_adapter(adapter), unit->fcp_lun, unit->port->wwpn); - zfcp_scsi_queuecommand_fake(scpnt, adapter); + retval = SCSI_MLQUEUE_DEVICE_BUSY; goto out; } - atomic_inc(&adapter->scsi_reqs_active); - temp_ret = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, ZFCP_REQ_AUTO_CLEANUP); - if (temp_ret < 0) { + if (unlikely(temp_ret < 0)) { ZFCP_LOG_DEBUG("error: Could not send a Send FCP Command\n"); - atomic_dec(&adapter->scsi_reqs_active); - wake_up(&adapter->scsi_reqs_active_wq); - zfcp_scsi_queuecommand_fake(scpnt, adapter); + retval = SCSI_MLQUEUE_HOST_BUSY; } else { #ifdef ZFCP_DEBUG_REQUESTS debug_text_event(adapter->req_dbf, 3, "q_scpnt"); @@ -524,7 +405,7 @@ zfcp_scsi_queuecommand(Scsi_Cmnd * scpnt #endif /* ZFCP_DEBUG_REQUESTS */ } out: - return 0; + return retval; } /* @@ -557,45 +438,6 @@ zfcp_unit_lookup(struct zfcp_adapter *ad } /* - * function: zfcp_scsi_potential_abort_on_fake - * - * purpose: - * - * returns: 0 - no fake request aborted - * 1 - fake request was aborted - * - * context: both the adapter->abort_lock and the - * adapter->fake_list_lock are assumed to be held write lock - * irqsave - */ -int -zfcp_scsi_potential_abort_on_fake(struct zfcp_adapter *adapter, - Scsi_Cmnd * cmnd) -{ - Scsi_Cmnd *cur = adapter->first_fake_cmnd; - Scsi_Cmnd *pre = NULL; - int retval = 0; - - while (cur) { - if (cur == cmnd) { - if (pre) - pre->host_scribble = cur->host_scribble; - else - adapter->first_fake_cmnd = - (Scsi_Cmnd *) cur->host_scribble; - cur->host_scribble = NULL; - if (!adapter->first_fake_cmnd) - del_timer(&adapter->fake_scsi_timer); - retval = 1; - break; - } - pre = cur; - cur = (Scsi_Cmnd *) cur->host_scribble; - } - return retval; -} - -/* * function: zfcp_scsi_eh_abort_handler * * purpose: tries to abort the specified (timed out) SCSI command @@ -663,34 +505,12 @@ zfcp_scsi_eh_abort_handler(Scsi_Cmnd * s * Race condition between normal (late) completion and abort has * to be avoided. * The entirity of all accesses to scsi_req have to be atomic. - * scsi_req is usually part of the fsf_req (for requests which - * are not faked) and thus we block the release of fsf_req - * as long as we need to access scsi_req. - * For faked commands we use the same lock even if they are not - * put into the fsf_req queue. This makes implementation - * easier. + * scsi_req is usually part of the fsf_req and thus we block the + * release of fsf_req as long as we need to access scsi_req. */ write_lock_irqsave(&adapter->abort_lock, flags); /* - * Check if we deal with a faked command, which we may just forget - * about from now on - */ - write_lock(&adapter->fake_list_lock); - /* only need to go through list if there are faked requests */ - if (adapter->first_fake_cmnd != NULL) { - if (zfcp_scsi_potential_abort_on_fake(adapter, scpnt)) { - write_unlock(&adapter->fake_list_lock); - write_unlock_irqrestore(&adapter->abort_lock, flags); - ZFCP_LOG_INFO("A faked command was aborted\n"); - retval = SUCCESS; - strncpy(dbf_result, "##faked", ZFCP_ABORT_DBF_LENGTH); - goto out; - } - } - write_unlock(&adapter->fake_list_lock); - - /* * Check whether command has just completed and can not be aborted. * Even if the command has just been completed late, we can access * scpnt since the SCSI stack does not release it at least until @@ -845,11 +665,6 @@ zfcp_scsi_eh_device_reset_handler(Scsi_C spin_unlock_irq(scsi_host->host_lock); - /* - * We should not be called to reset a target which we 'sent' faked SCSI - * commands since the abort of faked SCSI commands should always - * succeed (simply delete timer). - */ if (!unit) { ZFCP_LOG_NORMAL("bug: Tried to reset a non existant unit.\n"); retval = SUCCESS; @@ -1023,7 +838,6 @@ zfcp_adapter_scsi_register(struct zfcp_a retval = -EIO; goto out; } - atomic_set_mask(ZFCP_STATUS_ADAPTER_REGISTERED, &adapter->status); ZFCP_LOG_DEBUG("host registered, scsi_host at 0x%lx\n", (unsigned long) adapter->scsi_host); @@ -1039,7 +853,12 @@ zfcp_adapter_scsi_register(struct zfcp_a */ adapter->scsi_host->hostdata[0] = (unsigned long) adapter; - scsi_add_host(adapter->scsi_host, &adapter->ccw_device->dev); + if (scsi_add_host(adapter->scsi_host, &adapter->ccw_device->dev)) { + scsi_host_put(adapter->scsi_host); + retval = -EIO; + goto out; + } + atomic_set_mask(ZFCP_STATUS_ADAPTER_REGISTERED, &adapter->status); out: return retval; } @@ -1061,8 +880,9 @@ zfcp_adapter_scsi_unregister(struct zfcp return; scsi_remove_host(shost); scsi_host_put(shost); - adapter->scsi_host = NULL; + atomic_clear_mask(ZFCP_STATUS_ADAPTER_REGISTERED, &adapter->status); + return; } diff -puN drivers/s390/scsi/zfcp_sysfs_adapter.c~s390-07-zfcp-host-adapter drivers/s390/scsi/zfcp_sysfs_adapter.c --- 25/drivers/s390/scsi/zfcp_sysfs_adapter.c~s390-07-zfcp-host-adapter Thu Jan 8 14:11:34 2004 +++ 25-akpm/drivers/s390/scsi/zfcp_sysfs_adapter.c Thu Jan 8 14:11:34 2004 @@ -25,7 +25,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#define ZFCP_SYSFS_ADAPTER_C_REVISION "$Revision: 1.21 $" +#define ZFCP_SYSFS_ADAPTER_C_REVISION "$Revision: 1.26 $" #include #include "zfcp_ext.h" @@ -155,11 +155,8 @@ zfcp_sysfs_port_add_store(struct device retval = 0; - zfcp_adapter_get(adapter); - - /* try to open port only if adapter is online */ - if (adapter->ccw_device->online == 1) - zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED); + zfcp_erp_port_reopen(port, 0); + zfcp_erp_wait(port->adapter); zfcp_port_put(port); out: up(&zfcp_data.config_sema); @@ -219,6 +216,8 @@ zfcp_sysfs_port_remove_store(struct devi zfcp_erp_port_shutdown(port, 0); zfcp_erp_wait(adapter); zfcp_port_put(port); + zfcp_sysfs_port_remove_files(&port->sysfs_device, + atomic_read(&port->status)); device_unregister(&port->sysfs_device); out: up(&zfcp_data.config_sema); @@ -268,6 +267,7 @@ zfcp_sysfs_adapter_failed_store(struct d zfcp_erp_modify_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED); + zfcp_erp_wait(adapter); out: up(&zfcp_data.config_sema); return retval ? retval : count; diff -puN drivers/s390/scsi/zfcp_sysfs_port.c~s390-07-zfcp-host-adapter drivers/s390/scsi/zfcp_sysfs_port.c --- 25/drivers/s390/scsi/zfcp_sysfs_port.c~s390-07-zfcp-host-adapter Thu Jan 8 14:11:34 2004 +++ 25-akpm/drivers/s390/scsi/zfcp_sysfs_port.c Thu Jan 8 14:11:34 2004 @@ -25,7 +25,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#define ZFCP_SYSFS_PORT_C_REVISION "$Revision: 1.26 $" +#define ZFCP_SYSFS_PORT_C_REVISION "$Revision: 1.32 $" #include #include @@ -110,11 +110,9 @@ zfcp_sysfs_unit_add_store(struct device retval = 0; - zfcp_port_get(port); - - /* try to open unit only if adapter is online */ - if (port->adapter->ccw_device->online == 1) - zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED); + zfcp_erp_unit_reopen(unit, 0); + zfcp_erp_wait(unit->port->adapter); + wait_event(unit->scsi_add_wq, atomic_read(&unit->scsi_add_work) == 0); zfcp_unit_put(unit); out: up(&zfcp_data.config_sema); @@ -170,6 +168,7 @@ zfcp_sysfs_unit_remove_store(struct devi zfcp_erp_unit_shutdown(unit, 0); zfcp_erp_wait(unit->port->adapter); zfcp_unit_put(unit); + zfcp_sysfs_unit_remove_files(&unit->sysfs_device); device_unregister(&unit->sysfs_device); out: up(&zfcp_data.config_sema); @@ -217,6 +216,7 @@ zfcp_sysfs_port_failed_store(struct devi } zfcp_erp_modify_port_status(port, ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED); + zfcp_erp_wait(port->adapter); out: up(&zfcp_data.config_sema); return retval ? retval : count; @@ -293,7 +293,7 @@ static struct attribute_group zfcp_port_ }; /** - * zfcp_sysfs_create_port_files - create sysfs port files + * zfcp_sysfs_port_create_files - create sysfs port files * @dev: pointer to belonging device * * Create all attributes of the sysfs representation of a port. @@ -315,5 +315,19 @@ zfcp_sysfs_port_create_files(struct devi return retval; } +/** + * zfcp_sysfs_port_remove_files - remove sysfs port files + * @dev: pointer to belonging device + * + * Remove all attributes of the sysfs representation of a port. + */ +void +zfcp_sysfs_port_remove_files(struct device *dev, u32 flags) +{ + sysfs_remove_group(&dev->kobj, &zfcp_port_common_attr_group); + if (!(flags & ZFCP_STATUS_PORT_NAMESERVER)) + sysfs_remove_group(&dev->kobj, &zfcp_port_no_ns_attr_group); +} + #undef ZFCP_LOG_AREA #undef ZFCP_LOG_AREA_PREFIX diff -puN drivers/s390/scsi/zfcp_sysfs_unit.c~s390-07-zfcp-host-adapter drivers/s390/scsi/zfcp_sysfs_unit.c --- 25/drivers/s390/scsi/zfcp_sysfs_unit.c~s390-07-zfcp-host-adapter Thu Jan 8 14:11:34 2004 +++ 25-akpm/drivers/s390/scsi/zfcp_sysfs_unit.c Thu Jan 8 14:11:34 2004 @@ -25,7 +25,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#define ZFCP_SYSFS_UNIT_C_REVISION "$Revision: 1.17 $" +#define ZFCP_SYSFS_UNIT_C_REVISION "$Revision: 1.19 $" #include #include @@ -186,5 +186,17 @@ zfcp_sysfs_unit_create_files(struct devi return sysfs_create_group(&dev->kobj, &zfcp_unit_attr_group); } +/** + * zfcp_sysfs_remove_unit_files - remove sysfs unit files + * @dev: pointer to belonging device + * + * Remove all attributes of the sysfs representation of a unit. + */ +void +zfcp_sysfs_unit_remove_files(struct device *dev) +{ + sysfs_remove_group(&dev->kobj, &zfcp_unit_attr_group); +} + #undef ZFCP_LOG_AREA #undef ZFCP_LOG_AREA_PREFIX _