X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fs390%2Fscsi%2Fzfcp_fsf.c;h=44c646cca364799248af0f5d7c10da18152c9dd2;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=79451af65f5e05e8dbf0612c51cc9f32199820c1;hpb=9bf4aaab3e101692164d49b7ca357651eb691cb6;p=linux-2.6.git diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 79451af65..44c646cca 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -29,11 +29,12 @@ */ /* 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 *); @@ -48,7 +49,7 @@ static int zfcp_fsf_status_read_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); @@ -79,10 +80,9 @@ static u32 fsf_qtcb_type[] = { }; static const char zfcp_act_subtable_type[5][8] = { - {"unknown"}, {"OS"}, {"WWPN"}, {"DID"}, {"LUN"} + "unknown", "OS", "WWPN", "DID", "LUN" }; - /****************************************************************/ /*************** FSF related Functions *************************/ /****************************************************************/ @@ -684,13 +684,11 @@ zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *fsf_req) 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: @@ -785,6 +783,11 @@ zfcp_fsf_req_dispatch(struct zfcp_fsf_req *fsf_req) 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); @@ -1624,26 +1627,6 @@ zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *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 " @@ -1665,9 +1648,10 @@ zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req) } 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; } @@ -1769,7 +1753,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) 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", @@ -1863,6 +1847,10 @@ static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req) /* 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"); @@ -1921,15 +1909,6 @@ static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req) 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 " @@ -1971,8 +1950,6 @@ skip_fsfstatus: if (send_els->handler != 0) send_els->handler(send_els->handler_data); - kfree(send_els); - return retval; } @@ -2219,6 +2196,111 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req) 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 * @@ -3319,19 +3401,19 @@ zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *fsf_req) 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; @@ -3486,7 +3568,7 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, * 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", @@ -3788,44 +3870,6 @@ zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req) 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 @@ -4157,87 +4201,6 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) } 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); @@ -4585,16 +4548,6 @@ zfcp_fsf_control_file_handler(struct zfcp_fsf_req *fsf_req) 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( @@ -4682,8 +4635,8 @@ zfcp_fsf_req_wait_and_cleanup(struct zfcp_fsf_req *fsf_req, } 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)) @@ -4712,30 +4665,25 @@ zfcp_fsf_req_qtcb_init(struct zfcp_fsf_req *fsf_req, u32 fsf_cmd) * 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; }