|
@@ -554,6 +554,17 @@ static void
|
|
zfcp_fsf_link_down_info_eval(struct zfcp_adapter *adapter,
|
|
zfcp_fsf_link_down_info_eval(struct zfcp_adapter *adapter,
|
|
struct fsf_link_down_info *link_down)
|
|
struct fsf_link_down_info *link_down)
|
|
{
|
|
{
|
|
|
|
+ if (atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
|
|
|
|
+ &adapter->status))
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status);
|
|
|
|
+
|
|
|
|
+ if (link_down == NULL) {
|
|
|
|
+ zfcp_erp_adapter_reopen(adapter, 0);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
switch (link_down->error_code) {
|
|
switch (link_down->error_code) {
|
|
case FSF_PSQ_LINK_NO_LIGHT:
|
|
case FSF_PSQ_LINK_NO_LIGHT:
|
|
ZFCP_LOG_NORMAL("The local link to adapter %s is down "
|
|
ZFCP_LOG_NORMAL("The local link to adapter %s is down "
|
|
@@ -634,20 +645,15 @@ zfcp_fsf_link_down_info_eval(struct zfcp_adapter *adapter,
|
|
link_down->explanation_code,
|
|
link_down->explanation_code,
|
|
link_down->vendor_specific_code);
|
|
link_down->vendor_specific_code);
|
|
|
|
|
|
- if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
|
|
|
|
- &adapter->status)) {
|
|
|
|
- atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
|
|
|
|
- &adapter->status);
|
|
|
|
- switch (link_down->error_code) {
|
|
|
|
- case FSF_PSQ_LINK_NO_LIGHT:
|
|
|
|
- case FSF_PSQ_LINK_WRAP_PLUG:
|
|
|
|
- case FSF_PSQ_LINK_NO_FCP:
|
|
|
|
- case FSF_PSQ_LINK_FIRMWARE_UPDATE:
|
|
|
|
- zfcp_erp_adapter_reopen(adapter, 0);
|
|
|
|
- break;
|
|
|
|
- default:
|
|
|
|
- zfcp_erp_adapter_failed(adapter);
|
|
|
|
- }
|
|
|
|
|
|
+ switch (link_down->error_code) {
|
|
|
|
+ case FSF_PSQ_LINK_NO_LIGHT:
|
|
|
|
+ case FSF_PSQ_LINK_WRAP_PLUG:
|
|
|
|
+ case FSF_PSQ_LINK_NO_FCP:
|
|
|
|
+ case FSF_PSQ_LINK_FIRMWARE_UPDATE:
|
|
|
|
+ zfcp_erp_adapter_reopen(adapter, 0);
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ zfcp_erp_adapter_failed(adapter);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -919,30 +925,36 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req)
|
|
case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK:
|
|
case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK:
|
|
ZFCP_LOG_INFO("Physical link to adapter %s is down\n",
|
|
ZFCP_LOG_INFO("Physical link to adapter %s is down\n",
|
|
zfcp_get_busid_by_adapter(adapter));
|
|
zfcp_get_busid_by_adapter(adapter));
|
|
|
|
+ zfcp_fsf_link_down_info_eval(adapter,
|
|
|
|
+ (struct fsf_link_down_info *)
|
|
|
|
+ &status_buffer->payload);
|
|
break;
|
|
break;
|
|
case FSF_STATUS_READ_SUB_FDISC_FAILED:
|
|
case FSF_STATUS_READ_SUB_FDISC_FAILED:
|
|
ZFCP_LOG_INFO("Local link to adapter %s is down "
|
|
ZFCP_LOG_INFO("Local link to adapter %s is down "
|
|
"due to failed FDISC login\n",
|
|
"due to failed FDISC login\n",
|
|
- zfcp_get_busid_by_adapter(adapter));
|
|
|
|
|
|
+ zfcp_get_busid_by_adapter(adapter));
|
|
|
|
+ zfcp_fsf_link_down_info_eval(adapter,
|
|
|
|
+ (struct fsf_link_down_info *)
|
|
|
|
+ &status_buffer->payload);
|
|
break;
|
|
break;
|
|
case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE:
|
|
case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE:
|
|
ZFCP_LOG_INFO("Local link to adapter %s is down "
|
|
ZFCP_LOG_INFO("Local link to adapter %s is down "
|
|
"due to firmware update on adapter\n",
|
|
"due to firmware update on adapter\n",
|
|
zfcp_get_busid_by_adapter(adapter));
|
|
zfcp_get_busid_by_adapter(adapter));
|
|
|
|
+ zfcp_fsf_link_down_info_eval(adapter, NULL);
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
ZFCP_LOG_INFO("Local link to adapter %s is down "
|
|
ZFCP_LOG_INFO("Local link to adapter %s is down "
|
|
"due to unknown reason\n",
|
|
"due to unknown reason\n",
|
|
zfcp_get_busid_by_adapter(adapter));
|
|
zfcp_get_busid_by_adapter(adapter));
|
|
|
|
+ zfcp_fsf_link_down_info_eval(adapter, NULL);
|
|
};
|
|
};
|
|
- zfcp_fsf_link_down_info_eval(adapter,
|
|
|
|
- (struct fsf_link_down_info *) &status_buffer->payload);
|
|
|
|
break;
|
|
break;
|
|
|
|
|
|
case FSF_STATUS_READ_LINK_UP:
|
|
case FSF_STATUS_READ_LINK_UP:
|
|
ZFCP_LOG_NORMAL("Local link to adapter %s was replugged. "
|
|
ZFCP_LOG_NORMAL("Local link to adapter %s was replugged. "
|
|
- "Restarting operations on this adapter\n",
|
|
|
|
- zfcp_get_busid_by_adapter(adapter));
|
|
|
|
|
|
+ "Restarting operations on this adapter\n",
|
|
|
|
+ zfcp_get_busid_by_adapter(adapter));
|
|
/* All ports should be marked as ready to run again */
|
|
/* All ports should be marked as ready to run again */
|
|
zfcp_erp_modify_adapter_status(adapter,
|
|
zfcp_erp_modify_adapter_status(adapter,
|
|
ZFCP_STATUS_COMMON_RUNNING,
|
|
ZFCP_STATUS_COMMON_RUNNING,
|
|
@@ -2191,13 +2203,10 @@ zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action,
|
|
return -EOPNOTSUPP;
|
|
return -EOPNOTSUPP;
|
|
}
|
|
}
|
|
|
|
|
|
- timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL);
|
|
|
|
- if (!timer)
|
|
|
|
- return -ENOMEM;
|
|
|
|
-
|
|
|
|
/* setup new FSF request */
|
|
/* setup new FSF request */
|
|
retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA,
|
|
retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA,
|
|
- 0, 0, &lock_flags, &fsf_req);
|
|
|
|
|
|
+ erp_action ? ZFCP_REQ_AUTO_CLEANUP : 0,
|
|
|
|
+ 0, &lock_flags, &fsf_req);
|
|
if (retval < 0) {
|
|
if (retval < 0) {
|
|
ZFCP_LOG_INFO("error: Out of resources. Could not create an "
|
|
ZFCP_LOG_INFO("error: Out of resources. Could not create an "
|
|
"exchange port data request for"
|
|
"exchange port data request for"
|
|
@@ -2205,25 +2214,33 @@ zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action,
|
|
zfcp_get_busid_by_adapter(adapter));
|
|
zfcp_get_busid_by_adapter(adapter));
|
|
write_unlock_irqrestore(&adapter->request_queue.queue_lock,
|
|
write_unlock_irqrestore(&adapter->request_queue.queue_lock,
|
|
lock_flags);
|
|
lock_flags);
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (erp_action) {
|
|
|
|
- erp_action->fsf_req = fsf_req;
|
|
|
|
- fsf_req->erp_action = erp_action;
|
|
|
|
|
|
+ return retval;
|
|
}
|
|
}
|
|
|
|
|
|
if (data)
|
|
if (data)
|
|
- fsf_req->data = (unsigned long) data;
|
|
|
|
|
|
+ fsf_req->data = (unsigned long) data;
|
|
|
|
|
|
sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
|
|
sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
|
|
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
|
|
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
|
|
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
|
|
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
|
|
|
|
|
|
- init_timer(timer);
|
|
|
|
- timer->function = zfcp_fsf_request_timeout_handler;
|
|
|
|
- timer->data = (unsigned long) adapter;
|
|
|
|
- timer->expires = ZFCP_FSF_REQUEST_TIMEOUT;
|
|
|
|
|
|
+ if (erp_action) {
|
|
|
|
+ erp_action->fsf_req = fsf_req;
|
|
|
|
+ fsf_req->erp_action = erp_action;
|
|
|
|
+ timer = &erp_action->timer;
|
|
|
|
+ } else {
|
|
|
|
+ timer = kmalloc(sizeof(struct timer_list), GFP_ATOMIC);
|
|
|
|
+ if (!timer) {
|
|
|
|
+ write_unlock_irqrestore(&adapter->request_queue.queue_lock,
|
|
|
|
+ lock_flags);
|
|
|
|
+ zfcp_fsf_req_free(fsf_req);
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+ }
|
|
|
|
+ init_timer(timer);
|
|
|
|
+ timer->function = zfcp_fsf_request_timeout_handler;
|
|
|
|
+ timer->data = (unsigned long) adapter;
|
|
|
|
+ timer->expires = ZFCP_FSF_REQUEST_TIMEOUT;
|
|
|
|
+ }
|
|
|
|
|
|
retval = zfcp_fsf_req_send(fsf_req, timer);
|
|
retval = zfcp_fsf_req_send(fsf_req, timer);
|
|
if (retval) {
|
|
if (retval) {
|
|
@@ -2233,23 +2250,22 @@ zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action,
|
|
zfcp_fsf_req_free(fsf_req);
|
|
zfcp_fsf_req_free(fsf_req);
|
|
if (erp_action)
|
|
if (erp_action)
|
|
erp_action->fsf_req = NULL;
|
|
erp_action->fsf_req = NULL;
|
|
|
|
+ else
|
|
|
|
+ kfree(timer);
|
|
write_unlock_irqrestore(&adapter->request_queue.queue_lock,
|
|
write_unlock_irqrestore(&adapter->request_queue.queue_lock,
|
|
lock_flags);
|
|
lock_flags);
|
|
- goto out;
|
|
|
|
|
|
+ return retval;
|
|
}
|
|
}
|
|
|
|
|
|
- ZFCP_LOG_DEBUG("Exchange Port Data request initiated (adapter %s)\n",
|
|
|
|
- zfcp_get_busid_by_adapter(adapter));
|
|
|
|
-
|
|
|
|
- write_unlock_irqrestore(&adapter->request_queue.queue_lock,
|
|
|
|
- lock_flags);
|
|
|
|
|
|
+ write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
|
|
|
|
|
|
- wait_event(fsf_req->completion_wq,
|
|
|
|
- fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
|
|
|
|
- del_timer_sync(timer);
|
|
|
|
- zfcp_fsf_req_free(fsf_req);
|
|
|
|
- out:
|
|
|
|
- kfree(timer);
|
|
|
|
|
|
+ if (!erp_action) {
|
|
|
|
+ wait_event(fsf_req->completion_wq,
|
|
|
|
+ fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
|
|
|
|
+ del_timer_sync(timer);
|
|
|
|
+ zfcp_fsf_req_free(fsf_req);
|
|
|
|
+ kfree(timer);
|
|
|
|
+ }
|
|
return retval;
|
|
return retval;
|
|
}
|
|
}
|
|
|
|
|