*/
/* this drivers version (do not edit !!! generated and updated by cvs) */
-#define ZFCP_FSF_C_REVISION "$Revision: 1.55 $"
+#define ZFCP_FSF_C_REVISION "$Revision: 1.65 $"
#include "zfcp_ext.h"
static int zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *);
+static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *);
static int zfcp_fsf_open_port_handler(struct zfcp_fsf_req *);
static int zfcp_fsf_close_port_handler(struct zfcp_fsf_req *);
static int zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *);
static int zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *);
static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *);
static int zfcp_fsf_control_file_handler(struct zfcp_fsf_req *);
-static inline int zfcp_fsf_req_create_sbal_check(
+static inline int zfcp_fsf_req_sbal_check(
unsigned long *, struct zfcp_qdio_queue *, int);
static inline int zfcp_use_one_sbal(
struct scatterlist *, int, struct scatterlist *, int);
};
static const char zfcp_act_subtable_type[5][8] = {
- {"unknown"}, {"OS"}, {"WWPN"}, {"DID"}, {"LUN"}
+ "unknown", "OS", "WWPN", "DID", "LUN"
};
-
/****************************************************************/
/*************** FSF related Functions *************************/
/****************************************************************/
break;
case FSF_SQ_ULP_PROGRAMMING_ERROR:
ZFCP_LOG_FLAGS(0, "FSF_SQ_ULP_PROGRAMMING_ERROR\n");
- ZFCP_LOG_NORMAL("bug: An illegal amount of data was attempted "
- "to be sent to the adapter %s "
- "Stopping all operations on this adapter. ",
+ ZFCP_LOG_NORMAL("error: not enough SBALs for data transfer "
+ "(adapter %s)\n",
zfcp_get_busid_by_adapter(fsf_req->adapter));
debug_text_exception(fsf_req->adapter->erp_dbf, 0,
"fsf_sq_ulp_err");
- zfcp_erp_adapter_shutdown(fsf_req->adapter, 0);
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
zfcp_fsf_exchange_config_data_handler(fsf_req);
break;
+ case FSF_QTCB_EXCHANGE_PORT_DATA :
+ ZFCP_LOG_FLAGS(2, "FSF_QTCB_EXCHANGE_PORT_DATA\n");
+ zfcp_fsf_exchange_port_data_handler(fsf_req);
+ break;
+
case FSF_QTCB_SEND_ELS :
ZFCP_LOG_FLAGS(2, "FSF_QTCB_SEND_ELS\n");
zfcp_fsf_send_els_handler(fsf_req);
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
- case FSF_REQUEST_BUF_NOT_VALID :
- ZFCP_LOG_FLAGS(2, "FSF_REQUEST_BUF_NOT_VALID\n");
- ZFCP_LOG_NORMAL("error: The port 0x%016Lx on adapter %s has "
- "rejected a generic services command "
- "due to invalid request buffer.\n",
- port->wwpn, zfcp_get_busid_by_port(port));
- debug_text_event(adapter->erp_dbf, 1, "fsf_s_reqiv");
- fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
- break;
-
- case FSF_RESPONSE_BUF_NOT_VALID :
- ZFCP_LOG_FLAGS(2, "FSF_RESPONSE_BUF_NOT_VALID\n");
- ZFCP_LOG_NORMAL("error: The port 0x%016Lx on adapter %s has "
- "rejected a generic services command "
- "due to invalid response buffer.\n",
- port->wwpn, zfcp_get_busid_by_port(port));
- debug_text_event(adapter->erp_dbf, 1, "fsf_s_resiv");
- fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
- break;
-
case FSF_PORT_BOXED :
ZFCP_LOG_FLAGS(2, "FSF_PORT_BOXED\n");
ZFCP_LOG_INFO("The remote port 0x%016Lx on adapter %s "
}
skip_fsfstatus:
- if (send_ct->handler != NULL) {
+ send_ct->status = retval;
+
+ if (send_ct->handler != NULL)
send_ct->handler(send_ct->handler_data);
- }
return retval;
}
sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
/* start QDIO request for this FSF request */
- ret = zfcp_fsf_req_send(fsf_req, NULL);
+ ret = zfcp_fsf_req_send(fsf_req, els->timer);
if (ret) {
ZFCP_LOG_DEBUG("error: initiation of ELS request failed "
"(adapter %s, port 0x%016Lx)\n",
/* ERP strategy will escalate */
debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ulp");
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ retval =
+ zfcp_handle_els_rjt(header->fsf_status_qual.word[1],
+ (struct zfcp_ls_rjt_par *)
+ &header->fsf_status_qual.word[2]);
break;
case FSF_SQ_RETRY_IF_POSSIBLE:
ZFCP_LOG_FLAGS(2, "FSF_SQ_RETRY_IF_POSSIBLE\n");
bottom->resp_buf_length);
break;
- case FSF_UNKNOWN_COMMAND:
- ZFCP_LOG_FLAGS(2, "FSF_UNKNOWN_COMMAND\n");
- ZFCP_LOG_INFO(
- "FSF command 0x%x is not supported by FCP adapter "
- "(adapter: %s)\n", fsf_req->fsf_command,
- zfcp_get_busid_by_port(port));
- fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
- break;
-
case FSF_ACCESS_DENIED:
ZFCP_LOG_FLAGS(2, "FSF_ACCESS_DENIED\n");
ZFCP_LOG_NORMAL("Access denied, cannot send ELS "
if (send_els->handler != 0)
send_els->handler(send_els->handler_data);
- kfree(send_els);
-
return retval;
}
return 0;
}
+/**
+ * zfcp_fsf_exchange_port_data - request information about local port
+ * @adapter: for which port data is requested
+ * @data: response to exchange port data request
+ */
+int
+zfcp_fsf_exchange_port_data(struct zfcp_adapter *adapter,
+ struct fsf_qtcb_bottom_port *data)
+{
+ volatile struct qdio_buffer_element *sbale;
+ int retval = 0;
+ unsigned long lock_flags;
+ struct zfcp_fsf_req *fsf_req;
+ struct timer_list *timer;
+
+ if(!(adapter->supported_features & FSF_FEATURE_HBAAPI_MANAGEMENT)){
+ ZFCP_LOG_INFO("error: exchange port data "
+ "command not supported by adapter %s\n",
+ zfcp_get_busid_by_adapter(adapter));
+ return -EOPNOTSUPP;
+ }
+
+ timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL);
+ if (!timer)
+ return -ENOMEM;
+
+ /* setup new FSF request */
+ retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA,
+ 0, 0, &lock_flags, &fsf_req);
+ if (retval < 0) {
+ ZFCP_LOG_INFO("error: Out of resources. Could not create an "
+ "exchange port data request for"
+ "the adapter %s.\n",
+ zfcp_get_busid_by_adapter(adapter));
+ write_unlock_irqrestore(&adapter->request_queue.queue_lock,
+ lock_flags);
+ goto out;
+ }
+
+ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+ sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+ sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+
+ fsf_req->data.port_data = data;
+
+ 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);
+ if (retval) {
+ ZFCP_LOG_INFO("error: Could not send an exchange port data "
+ "command on the adapter %s\n",
+ zfcp_get_busid_by_adapter(adapter));
+ zfcp_fsf_req_free(fsf_req);
+ write_unlock_irqrestore(&adapter->request_queue.queue_lock,
+ lock_flags);
+ goto out;
+ }
+
+ 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);
+
+ wait_event(fsf_req->completion_wq,
+ fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
+ del_timer_sync(timer);
+ zfcp_fsf_req_cleanup(fsf_req);
+ out:
+ kfree(timer);
+ return retval;
+}
+
+
+/**
+ * zfcp_fsf_exchange_port_data_handler - handler for exchange_port_data request
+ * @fsf_req: pointer to struct zfcp_fsf_req
+ */
+static void
+zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *fsf_req)
+{
+ struct fsf_qtcb_bottom_port *bottom;
+ struct fsf_qtcb_bottom_port *data = fsf_req->data.port_data;
+
+ if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)
+ return;
+
+ switch (fsf_req->qtcb->header.fsf_status) {
+ case FSF_GOOD :
+ ZFCP_LOG_FLAGS(2,"FSF_GOOD\n");
+ bottom = &fsf_req->qtcb->bottom.port;
+ memcpy(data, bottom, sizeof(*data));
+ break;
+
+ default:
+ debug_text_event(fsf_req->adapter->erp_dbf, 0, "xchg-port-ng");
+ debug_event(fsf_req->adapter->erp_dbf, 0,
+ &fsf_req->qtcb->header.fsf_status, sizeof(u32));
+ }
+}
+
+
/*
* function: zfcp_fsf_open_port
*
return retval;
}
-/*
- * function: zfcp_fsf_send_fcp_command_task
- *
- * purpose:
- *
- * returns:
- *
- * note: we do not employ linked commands (not supported by HBA anyway)
+/**
+ * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command)
+ * @adapter: adapter where scsi command is issued
+ * @unit: unit where command is sent to
+ * @scsi_cmnd: scsi command to be sent
+ * @timer: timer to be started when request is initiated
+ * @req_flags: flags for fsf_request
*/
int
zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
struct zfcp_unit *unit,
- struct scsi_cmnd * scsi_cmnd, int req_flags)
+ struct scsi_cmnd * scsi_cmnd,
+ struct timer_list *timer, int req_flags)
{
struct zfcp_fsf_req *fsf_req = NULL;
struct fcp_cmnd_iu *fcp_cmnd_iu;
* start QDIO request for this FSF request
* covered by an SBALE)
*/
- retval = zfcp_fsf_req_send(fsf_req, NULL);
+ retval = zfcp_fsf_req_send(fsf_req, timer);
if (unlikely(retval < 0)) {
ZFCP_LOG_INFO("error: Could not send FCP command request "
"on adapter %s, port 0x%016Lx, unit 0x%016Lx\n",
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
- /* FIXME: this should be obsolete, isn' it? */
- case FSF_INBOUND_DATA_LENGTH_NOT_VALID:
- ZFCP_LOG_FLAGS(0, "FSF_INBOUND_DATA_LENGTH_NOT_VALID\n");
- ZFCP_LOG_NORMAL("bug: An invalid inbound data length field "
- "was found in a command for unit 0x%016Lx "
- "on port 0x%016Lx on adapter %s.\n",
- unit->fcp_lun,
- unit->port->wwpn, zfcp_get_busid_by_unit(unit));
- /* stop operation for this adapter */
- debug_text_event(fsf_req->adapter->erp_dbf, 0,
- "fsf_s_in_dl_nv");
- zfcp_erp_adapter_shutdown(unit->port->adapter, 0);
- zfcp_cmd_dbf_event_fsf("idleninv",
- fsf_req,
- &header->fsf_status_qual,
- sizeof (union fsf_status_qual));
- fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
- break;
-
- /* FIXME: this should be obsolete, isn' it? */
- case FSF_OUTBOUND_DATA_LENGTH_NOT_VALID:
- ZFCP_LOG_FLAGS(0, "FSF_OUTBOUND_DATA_LENGTH_NOT_VALID\n");
- ZFCP_LOG_NORMAL("bug: An invalid outbound data length field "
- "was found in a command unit 0x%016Lx on port "
- "0x%016Lx on adapter %s\n",
- unit->fcp_lun,
- unit->port->wwpn,
- zfcp_get_busid_by_unit(unit));
- /* stop operation for this adapter */
- debug_text_event(fsf_req->adapter->erp_dbf, 0,
- "fsf_s_out_dl_nv");
- zfcp_erp_adapter_shutdown(unit->port->adapter, 0);
- zfcp_cmd_dbf_event_fsf("odleninv", fsf_req,
- &header->fsf_status_qual,
- sizeof (union fsf_status_qual));
- fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
- break;
-
case FSF_CMND_LENGTH_NOT_VALID:
ZFCP_LOG_FLAGS(0, "FSF_CMND_LENGTH_NOT_VALID\n");
ZFCP_LOG_NORMAL
}
skip_fsfstatus:
-#if 0
- /*
- * This nasty chop at the problem is not working anymore
- * as we do not adjust the retry count anylonger in order
- * to have a number of retries that avoids I/O errors.
- * The manipulation of the retry count has been removed
- * in favour of a safe tape device handling. We must not
- * sent SCSI commands more than once to a device if no
- * retries are permitted by the high level driver. Generally
- * speaking, it was a mess to change retry counts. So it is
- * fine that this sort of workaround is gone.
- * Then, we had to face a certain number of immediate retries in case of
- * busy and queue full conditions (see below).
- * This is not acceptable
- * for the latter. Queue full conditions are used
- * by devices to indicate to a host that the host can rely
- * on the completion (or timeout) of at least one outstanding
- * command as a suggested trigger for command retries.
- * Busy conditions require a different trigger since
- * no commands are outstanding for that initiator from the
- * devices perspective.
- * The drawback of mapping a queue full condition to a
- * busy condition is the chance of wasting all retries prior
- * to the time when the device indicates that a command
- * rejected due to a queue full condition should be re-driven.
- * This case would lead to unnecessary I/O errors that
- * have to be considered fatal if for example ext3's
- * journaling would be torpedoed by such an avoidable
- * I/O error.
- * So, what issues are there with not mapping a queue-full
- * condition to a busy condition?
- * Due to the 'exclusive LUN'
- * policy enforced by the zSeries FCP channel, this
- * Linux instance is the only initiator with regard to
- * this adapter. It is safe to rely on the information
- * 'don't disturb me now ... and btw. no other commands
- * pending for you' (= queue full) sent by the LU,
- * since no other Linux can use this LUN via this adapter
- * at the same time. If there is a potential race
- * introduced by the FCP channel by not inhibiting Linux A
- * to give up a LU with commands pending while Linux B
- * grabs this LU and sends commands - thus providing
- * an exploit at the 'exclusive LUN' policy - then this
- * issue has to be considered a hardware problem. It should
- * be tracked as such if it really occurs. Even if the
- * FCP Channel spec. begs exploiters to wait for the
- * completion of all request sent to a LU prior to
- * closing this LU connection.
- * This spec. statement in conjunction with
- * the 'exclusive LUN' policy is not consistent design.
- * Another issue is how resource constraints for SCSI commands
- * might be handled by the FCP channel (just guessing for now).
- * If the FCP channel would always map resource constraints,
- * e.g. no free FC exchange ID due to I/O stress caused by
- * other sharing Linux instances, to faked queue-full
- * conditions then this would be a misinterpretation and
- * violation of SCSI standards.
- * If there are SCSI stack races as indicated below
- * then they need to be fixed just there.
- * Providing all issue above are not applicable or will
- * be fixed appropriately, removing the following hack
- * is the right thing to do.
- */
-
- /*
- * Note: This is a rather nasty chop at the problem. We cannot
- * risk adding to the mlqueue however as this will block the
- * device. If it is the last outstanding command for this host
- * it will remain blocked indefinitely. This would be quite possible
- * on the zSeries FCP adapter.
- * Also, there exists a race with scsi_insert_special relying on
- * scsi_request_fn to recalculate some command data which may not
- * happen when q->plugged is true in scsi_request_fn
- */
- if (status_byte(scpnt->result) == QUEUE_FULL) {
- ZFCP_LOG_DEBUG("Changing QUEUE_FULL to BUSY....\n");
- scpnt->result &= ~(QUEUE_FULL << 1);
- scpnt->result |= (BUSY << 1);
- }
-#endif
-
ZFCP_LOG_DEBUG("scpnt->result =0x%x\n", scpnt->result);
zfcp_cmd_dbf_event_scsi("response", scpnt);
retval = -EIO;
break;
- case FSF_UNKNOWN_COMMAND:
- ZFCP_LOG_FLAGS(2, "FSF_UNKNOWN_COMMAND\n");
- ZFCP_LOG_NORMAL(
- "FSF command 0x%x is not supported by the adapter %s\n",
- fsf_req->fsf_command,
- zfcp_get_busid_by_adapter(adapter));
- fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
- retval = -EINVAL;
- break;
-
case FSF_UNKNOWN_OP_SUBTYPE:
ZFCP_LOG_FLAGS(2, "FSF_UNKNOWN_OP_SUBTYPE\n");
ZFCP_LOG_NORMAL(
}
static inline int
-zfcp_fsf_req_create_sbal_check(unsigned long *flags,
- struct zfcp_qdio_queue *queue, int needed)
+zfcp_fsf_req_sbal_check(unsigned long *flags,
+ struct zfcp_qdio_queue *queue, int needed)
{
write_lock_irqsave(&queue->queue_lock, *flags);
if (likely(atomic_read(&queue->free_count) >= needed))
* zfcp_fsf_req_sbal_get - try to get one SBAL in the request queue
* @adapter: adapter for which request queue is examined
* @req_flags: flags indicating whether to wait for needed SBAL or not
- * @lock_flags: lock_flags is queue_lock is taken
- *
- * locking: on success the queue_lock for the request queue of the adapter
- * is held
+ * @lock_flags: lock_flags if queue_lock is taken
+ * Return: 0 on success, otherwise -EIO, or -ERESTARTSYS
+ * Locks: lock adapter->request_queue->queue_lock on success
*/
static int
zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter, int req_flags,
unsigned long *lock_flags)
{
- int condition;
+ long ret;
struct zfcp_qdio_queue *req_queue = &adapter->request_queue;
if (unlikely(req_flags & ZFCP_WAIT_FOR_SBAL)) {
- wait_event_interruptible_timeout(adapter->request_wq,
- (condition =
- zfcp_fsf_req_create_sbal_check
- (lock_flags, req_queue, 1)),
- ZFCP_SBAL_TIMEOUT);
- if (!condition) {
- return -EIO;
- }
- } else if (!zfcp_fsf_req_create_sbal_check(lock_flags, req_queue, 1)) {
+ ret = wait_event_interruptible_timeout(adapter->request_wq,
+ zfcp_fsf_req_sbal_check(lock_flags, req_queue, 1),
+ ZFCP_SBAL_TIMEOUT);
+ if (ret < 0)
+ return ret;
+ } else if (!zfcp_fsf_req_sbal_check(lock_flags, req_queue, 1))
return -EIO;
- }
return 0;
}