📄 initiator_rx.c
字号:
}#endif /* leave if command struct corresponding to task mgt rsp not found */ if (unlikely(related_command == NULL)) { goto out; } if (likely((header->response == FUNCTION_COMPLETE) || (header->response == TASK_DOES_NOT_EXIST) || (header->response == LUN_DOES_NOT_EXIST) || (header->response == FUNCTION_REJECTED))) { related_command->task_mgt_response = header->response; TRACE(TRACE_DEBUG, "Got task mgt response 0x%02x\n", header->response); } else { TRACE_ERROR("Invalid task mgt response from target 0x%02x," " returning reponse FUNCTION_REJECTED to SCSI\n", header->response); related_command->task_mgt_response = FUNCTION_REJECTED; } /* Added the TASK REASSIGN handling for connection recovery - SAI */ if (related_command->task_mgt_function == TMF_TASK_REASSIGN) { cmd = find_command_by_itt(related_command->ref_task_tag, current_connection); if (likely(cmd != NULL)) { /* Free the corresponding task mgt command */ if (related_command->task_mgt_response == FUNCTION_REJECTED) { /* TASK REASSIGN probably not supported. * Free pending command */ TRACE_ERROR ("Task Reassignment for task ITT %u, " "returned response %d\n", related_command->ref_task_tag, header->response); TRACE(TRACE_DEBUG, "Freeing related command, ITT %u\n", related_command->ref_task_tag); if (cmd->SCpnt != NULL) { /* pass the final status back up * to SCSI Mid-level */ cmd->SCpnt->result = DID_ERROR << 16; } cmd->cmd_state |= CMD_STATE_RXDONE; free_pending_command(cmd, current_connection); } } else { /* could not find the corresponding command -- * reject task mgt. command */ TRACE_ERROR("No task with ITT %u found\n", related_command->ref_task_tag); } TRACE(TRACE_DEBUG, "Freeing Task Mgt. request, ITT %u\n", related_command->init_task_tag); related_command->cmd_state |= CMD_STATE_RXDONE; free_pending_command(related_command, current_connection); current_session->n_rec_tasks--; } /* wake up the process waiting on task_mgt_sem semaphore */ up(¤t_connection->task_mgt_sem);out: TRACE(TRACE_ENTER_LEAVE, "Leave rx_task_mgt_rsp ,current_connection" " %p\n", current_connection); return 1; /* nothing but success here */}/*RFC 3720 Section 10.17.1 Reason (field in Reject Response) */static char *reject_reasons[] = { /* 0x02 */ "Data Digest Error", /* 0x03 */ "SNACK Reject", /* 0x04 */ "Protocol Error", /* 0x05 */ "Command not supported", /* 0x06 */ "Too many immediate commands", /* 0x07 */ "Task in progress", /* 0x08 */ "Invalid Data ACK", /* 0x09 */ "Invalid PDU field", /* 0x0a */ "Long Operation Reject", /* 0x0b */ "Negotiation Reset", /* 0x0c */ "Waiting for Logout" };/*************************************************************************** * executed only by rx thread. * the session->sess_lock MUST be held by the calling process/thread. * Called only by iscsi_initiator_rx_thread(). * This function processes the Reject header. * Parameters: current_connection which is a ptr to the connection struct * where the Reject header was received. * Return Value: 0 to terminate the rx thread gracefully, 1 to keep going ***************************************************************************/static intrx_rjt(struct connection *conn, __u32 size, char *buffer){ int retval = 1, found; __u32 local_itt; struct iscsi_targ_rjt *rjt_header; struct generic_pdu *bad_header; struct iscsi_init_snack *header; struct iscsi_init_scsi_cmnd *iscsi_cmd; struct command *related_command; struct session *sess; struct scsi_sense_data *senseinfo; char local_message[32], *local_ptr; TRACE(TRACE_ENTER_LEAVE, "Enter rx_rjt, conn %p\n", conn); sess = conn->my_session; rjt_header = (struct iscsi_targ_rjt *)conn->rx_buf; bad_header = (struct generic_pdu *)buffer; if (unlikely(rjt_header->reason < REASON_DATA_DIGEST_ERR || rjt_header->reason > REASON_WAITING_FOR_LOGOUT)) { sprintf(local_message, "out of range [0x%02x..0x%02x]", REASON_DATA_DIGEST_ERR, REASON_WAITING_FOR_LOGOUT); retval = 0; /* fatal */ local_ptr = local_message; } else { local_ptr = reject_reasons[rjt_header->reason - REASON_DATA_DIGEST_ERR]; if (rjt_header->reason >= REASON_PROTOCOL_ERR) retval = 0; /* fatal -- can't handle these yet */ } /* Reject does NOT have an ITT value (i.e., it is 0xffffffff) */ if (likely(bad_header != NULL && size >= ISCSI_HDR_LEN)) { local_itt = htonl(bad_header->init_task_tag); related_command = find_command_by_itt(local_itt, conn); TRACE_ERROR("Got Reject for ITT %u, reason 0x%02x: %s\n", local_itt, rjt_header->reason, local_ptr); printk("header of rejected pdu:\n"); dump_buffer((__u8 *)buffer, size); } else { local_itt = ALL_ONES; related_command = NULL; TRACE_ERROR("Got Reject with bad data, reason 0x%02x: %s\n", rjt_header->reason, local_ptr); }#ifdef ISCSI_CHECK_PDU_FORMAT /* Check that reserved fields are zero */ if (unlikely(!((rjt_header->flags & ~F_BIT) == 0 && rjt_header->rsvd2 == 0 && rjt_header->rsvd4 == 0 && rjt_header->rsvd5 == 0))) { reserved_not_0("Reject"); }#endif if (retval == 0) { /* look for reject of R2T SNACK previously sent on a write */ if (related_command != NULL && related_command->SCpnt != NULL && (bad_header->opcode & ISCSI_OPCODE)==ISCSI_INIT_SNACK && related_command->activity_flg == 2 && sess->oper_param->ErrorRecoveryLevel > 0 && sess->retran_period > 0 && related_command->SCpnt->sc_data_direction == SCSI_DATA_WRITE) { /* found it, don't let this Reject advance the StatSN, * then wake up tx thread to send Status SNACK */ conn->exp_stat_sn = ntohl(bad_header->exp_stat_sn); related_command->time_stamp -= sess->retran_period * HZ; if (atomic_read(&conn->tx_sem.count) <= 0) { /* get xmit thread going */ TRACE(TRACE_ISCSI_FULL, "rx_r2t: wake up tx thread\n"); up(&conn->tx_sem); } retval = 1; /* not fatal */ } goto rjt_out; } /* ignore target digest errors and wait for target to send out any * recovery R2Ts new 18_04 - SAI */ if (rjt_header->reason == REASON_DATA_DIGEST_ERR) { if ((iscsi_cmd=(struct iscsi_init_scsi_cmnd *)buffer) == NULL) { retval = 0; /* fatal */ goto rjt_out; } if (sess->retran_period > 0 && (iscsi_cmd->opcode & ISCSI_OPCODE) == ISCSI_INIT_SCSI_CMND) { /* pdu was a SCSI Command, so there must have been data * attached (to generate digest error), so it must have * been a write. Therefore, if this is the first such * reject, set timestamp so it will be reissued at once */ if (related_command) { related_command->time_stamp -= sess->retran_period * HZ; TRACE_ERROR("Reject due to Data Digest Error, " "retransmit command\n"); if (atomic_read(&conn->tx_sem.count) <= 0) { /* get xmit thread going */ TRACE(TRACE_ISCSI_FULL, "rx_r2t: wake up tx thread\n"); up(&conn->tx_sem); } goto rjt_out; } } TRACE_ERROR("Reject due to Data Digest Error, do nothing\n"); goto rjt_out; } /* for all other type of rejects, abort the related command - SAI */ if (unlikely(bad_header == NULL)) { TRACE_ERROR("Reject data buffer empty, ignore\n"); retval = 0; /* fatal */ goto rjt_out; } /* in case the rejected command was a SNACK */ header = (struct iscsi_init_snack *)buffer; if (unlikely(size < ISCSI_HDR_LEN)) { TRACE_ERROR ("Reject DSL = %u less than header length %u, ignore\n", size, ISCSI_HDR_LEN); retval = 0; /* fatal */ goto rjt_out; } if (rjt_header->reason == REASON_DATA_SNACK) { /* If the rejected SNACK is any other than Data/R2T * or Status, it's an error - SAI */ if (((header->flags & SNACK_TYPE) != DATA_R2T_SNACK) && ((header->flags & SNACK_TYPE) != STATUS_SNACK)) { TRACE_ERROR ("Expected Data/R2T or Status header in Reject PDU," " got type 0x%02x", (header->flags & SNACK_TYPE)); retval = 0; /* fatal */ goto rjt_out; } } /* if this ITT is not reserved, we should find a matching command */ found = 0; list_for_each_entry(related_command, &conn->pending_commands, link) { /* Status SNACK always has the ITT as ALL_ONES. * So for status snack, do not check for ITT -- * new 18_04 SAI */ if (rjt_header->reason == REASON_DATA_SNACK && (header->flags & SNACK_TYPE) == STATUS_SNACK) { if (related_command->snack_flags & STATUS_BIT) { /* Do not terminate on SNACK reject - SAI */ TRACE(TRACE_DEBUG, "Found corresponding Status SNACK request" " - ITT %u\n", related_command->init_task_tag); found = 1; break; } } else if (related_command->init_task_tag == local_itt) { found = 1; break; } } if (unlikely(found == 0)) { TRACE_ERROR("No command has matching ITT %u\n", local_itt); /* silently discard any snack rejects that appear delayed-SAI */ goto rjt_out; } /* all rejects should terminate the related command - SAI */ if (unlikely(related_command->SCpnt == NULL)) { if (related_command->header_opcode == ISCSI_INIT_SCSI_CMND) { /* No pointer to the SCSI Mid-level struct, bail out */ TRACE_ERROR("ITT %u command struct has SCpnt=NULL\n", local_itt); retval = 0; /* fatal */ } if (sess->oper_param->SessionType) { /* this is a discovery session, send a * logout to shut it down */ drive_logout(sess, conn, LOGOUT_CLOSE_SESSION); } } else { /* We need to increment the exp_stat_sn as we will * not receive the missing status anymore */ conn->exp_stat_sn++; related_command->SCpnt->result |= (DID_ERROR << 16); senseinfo = (struct scsi_sense_data *) related_command->SCpnt->sense_buffer; memset(senseinfo, 0, sizeof(struct scsi_sense_data)); /* Draft 20 Section 10.4.7.2 Sense Data * Shows table of sense values */ /* Valid Bit set, Response = 0x70 */ senseinfo->response = 0xf0; senseinfo->sense_key = ABORTED_COMMAND; /* Protocol CRC Error */ senseinfo->asl = 10; /* n-7 = 17-7 = 10 */ senseinfo->asc = 0x47; /* Protocol CRC Error Additional Sense Code */ senseinfo->ascq = 0x05; /* Protocol CRC Error Additional Sense Code qualifier */ related_command->SCpnt->result |= (DRIVER_SENSE << 24); } /* always free up the related command */ related_command->cmd_state |= CMD_STATE_RXDONE; free_pending_command(related_command, conn);rjt_out: TRACE(TRACE_ENTER_LEAVE, "Leave rx_rjt, retval %d\n", retval); return retval;}/*************************************************************************** * executed only by rx thread. * the session->sess_lock MUST be held by the calling process/thread. * Called only by iscsi_initiator_rx_thread(). * This function processes the NopIn header. * 4 combinations of ITT and TTT to look for (resvd value is 0xffffffff): *TTT ITT StatSN Respond *resvd resvd ? simple update to command window *resvd !=resvd +1 no response to NopOut sent by us *!=resvd resvd +0 yes provoke "ping" response from us *!=resvd !=resvd NA NA illegal * * Parameters: current_connection which is a ptr to the connection struct * where the NopIn header was received. * Return Value: >0 success (always) ***************************************************************************/static intrx_nopin(struct connection *current_connection, __u32 local_itt, struct command *related_command, __u32 size, char **buffer){ struct iscsi_targ_nopin *header; struct session *related_session; struct iscsi_init_nopout *nopout_cmd; __u32 lun; TRACE(TRACE_ENTER_LEAVE, "Enter rx_nopin, current_connection %p\n", current_connection); header = (struct iscsi_targ_nopin *) current_connection->rx_buf;#ifdef ISCSI_CHECK_PDU_FORMAT /* Check that reserved fields are zero */ if (unlikely(!((header->flags & ~F_BIT) == 0 && header->rsvd1 == 0 && header->rsvd2 == 0 && header->rsvd3 == 0))) { reserved_not_0("NopIn"); }#endif related_session = current_connection->my_session; if (unlikely(size > current_connection->max_send_length)) { /* don't send back more than target wants to get */ size = current_connection->max_send_length; } if (header->target_xfer_tag == ALL_ONES) { /* sent by target either as a response to a NopOut * sent earlier by us or as a means to update the * command window. In both cases, no response is * needed from the initiator. */ if (local_itt == ALL_ONES) { /* this is not a response to a NopOut sent * earlier by us, but is just a simple update * of the command window and this has already * been done, so we are finished. */ } else { /* this NopIn is a response to a NopOut sent * earlier by us */ if (related_command != NULL) { /* found the corresponding NopOut command, check it */ nopout_cmd = (struct iscsi_init_nopout *) &related_command->iscsi_cmd; if ((nopout_cmd->opcode & ISCSI_OPCODE) != ISCSI_INIT_NOP_OUT) { TRACE_ERROR ("Command matching NopIn has opcode"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -