📄 initiator_rx.c
字号:
local_itt, r2t_sn, offset, xfer_len); } else { TRACE_ERROR ("R2T for ITT %u has R2TSN %u, expected " "%u\n", local_itt, r2t_sn, related_command->r2t_sn); TRACE(TRACE_ERROR_RECOVERY, "expected offset %u, tot len %u\n", related_command->data_offset, related_command->SCpnt->request_bufflen); if (unlikely(TRACE_TEST(TRACE_ERROR_RECOVERY))) print_targ_r2t(r2t_header); /* R2TSN Sequence Error Recovery - SAI */ err_rec.curr_conn = current_connection; err_rec.related_cmd = related_command; err_rec.err_type = SEQUENCE_ERR; retval = init_do_error_recovery(&err_rec); goto rx_r2t_out; } } related_command->r2t_sn++; /* Draft 20, Section 10.7.4 Target Transfer Tag and LUN * "The Target Transfer Tag values are not specified by * this protocol except that the value 0xffffffff is * reserved and means that the Target Transfer Tag is * not supplied." */ if (unlikely(r2t_header->target_xfer_tag == ALL_ONES)) { TRACE_ERROR("R2T has reserved TTT value 0x%08x\n", r2t_header->target_xfer_tag); } if (unlikely(related_command->SCpnt == NULL)) { TRACE_ERROR("No SCSI command found for ITT %u\n", local_itt); } else if (unlikely(rx_pack_cookie_from_pdu(related_session, current_connection, related_command, r2t_header, local_itt,offset, xfer_len) < 0)) { TRACE_ERROR("Pack Cookie failed\n"); } } else { TRACE_ERROR("R2T for ITT %u, R2TSN %u, offset %u, DDTL %u, " "no command!\n", local_itt, r2t_sn, offset, xfer_len); } /* r2t exit added for Error Recovery - SAI */rx_r2t_out: TRACE(TRACE_ENTER_LEAVE, "Leave rx_r2t, current_connection %p, retval %d\n", current_connection, retval); return retval;}/* * Called only from rx_r2t(). * Populate a new cookie from an R2T PDU. Cookies are attached to the * command struct. Moved from rx_r2t to condense inline code * It extracts useful data from the R2T PDU and fills a new cookie. * Return 1 on success. * 0 on failure from create_r2t_cookie() */static int __attribute__ ((no_instrument_function))rx_pack_cookie_from_pdu( struct session *related_session, struct connection *current_connection, struct command *related_command , struct iscsi_targ_r2t *r2t_header, __u32 local_itt, __u32 offset, __u32 xfer_len){ struct r2t_cookie *cookie; int over_flow_data_size, r2t_sn, delta; TRACE(TRACE_ENTER_LEAVE, "Enter rx_pack_cookie\n"); r2t_sn = ntohl(r2t_header->r2t_sn); cookie = create_r2t_cookie(related_session); if (unlikely(cookie == NULL)) { TRACE_ERROR("Cookie for ITT %u, R2TSN %u FAILED\n", local_itt, r2t_sn); return 0; } /* copy info from R2T into fields in the cookie */ cookie->offset = offset; cookie->r2t_xfer_length = xfer_len; if (likely(related_session->oper_param->DataSequenceInOrder)) { /* DataSequenceInOrder=Yes */ /* Draft 20, Section 10.8 Ready to Transfer (R2T) * "DataSequenceInOrder governs the buffer offset ordering * in consecutive R2Ts. If DataSequenceInOrder is Yes, * then consecutive R2Ts MUST refer to continuous * non-overlapping ranges except for Recovery-R2Ts." */ /* Consider an out of seq R2T to be a recovery R2T - SAI */ delta = related_command->data_offset - offset; if (unlikely(delta != 0)) { /* Handle Recovery R2T without flagging errors - SAI */ if (likely(delta > 0)) { /* recovery R2T, just backup command offset */ TRACE_WARNING("Recovery R2T for ITT %u, " "R2TSN %u, reset offset from %u " "to %u, still_to_send from %u to %u\n", local_itt, r2t_sn, related_command->data_offset, offset, related_command->still_to_send, related_command->still_to_send + delta); related_command->still_to_send += delta; related_command->data_offset = offset; } else { TRACE_ERROR("R2T for ITT %u, R2TSN %u, has " "buffer offset %u, expected %u\n", local_itt, r2t_sn, offset, related_command->data_offset); /* put back this unneeded cookie structure */ uncreate_r2t_cookie(cookie, related_session); return -1; } } }#ifdef ISCSI_CHECK_PDU_FORMAT /* Check that R2T not asking to xfer more than MaxBurstLength */ if (unlikely(xfer_len > related_session->oper_param->MaxBurstLength)) { TRACE_ERROR ("R2T for ITT %u, R2TSN %u, has DDTL of %u bytes, " "exceeding allowed %s %u\n", local_itt, r2t_sn, xfer_len, "MaxBurstLength", related_session->oper_param->MaxBurstLength); /* for now, just ignore this error -- we can * handle data beyond MaxBurstLength without problem */ }#endif /* Check if this R2T would overflow the SCSI Mid-level buffers */ over_flow_data_size = offset + xfer_len - related_command->SCpnt->request_bufflen; if (unlikely(over_flow_data_size > 0)) { TRACE_ERROR("R2T for ITT %u, R2TSN %u, has DDTL of %u bytes " "that overflows SCSI buffer by %d\n", local_itt, r2t_sn, xfer_len, over_flow_data_size); /* accept only the remaining amount of buffer space */ if (over_flow_data_size >= xfer_len) { /* overflow exceeds amount to be transfered */ /* put back this unneeded cookie structure */ uncreate_r2t_cookie(cookie, related_session); return -1; } cookie->r2t_xfer_length -= over_flow_data_size; } TRACE(TRACE_DEBUG, "recvd r2t for ITT %u, R2TSN %u, offset %u, " "xfer length %u\n", local_itt, r2t_sn, related_command->data_offset, cookie->r2t_xfer_length); hookup_r2t_cookie(cookie, related_session, current_connection, related_command, r2t_header->target_xfer_tag); if (atomic_read(¤t_connection->tx_sem.count) <= 0) { /* tell xmit thread something may be ready to send */ TRACE(TRACE_ISCSI_FULL, "rx_r2t: wake up tx thread\n"); up(¤t_connection->tx_sem); } TRACE(TRACE_ENTER_LEAVE, "Leave rx_pack_cookie\n"); return 1;}/**************************************************************************** * 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 Asynchronous Message PDU * Parameters: current_connection which is a ptr to the connection struct * where the PDU header was received. * Return Value: >0 success, =0 failure. ****************************************************************************/static intrx_async_msg(struct connection *current_connection, __u32 size, char *buffer){ struct iscsi_targ_async_msg *am_header; struct session *related_session; struct connection *conn; __u32 lun; int retval = 0; /* assume this fails */ __u16 param1, param2, param3; TRACE(TRACE_ENTER_LEAVE, "Enter rx_async_msg, current_connection %p\n", current_connection); am_header = (struct iscsi_targ_async_msg *) current_connection->rx_buf; if (unlikely(TRACE_TEST(TRACE_DEBUG))) { debug_print_ip(current_connection, "Async Msg"); } related_session = current_connection->my_session;#ifdef ISCSI_CHECK_PDU_FORMAT /* Check if reserved fields are zero or not */ if (unlikely(!(((am_header->flags & ~F_BIT) == 0) && (am_header->rsvd2 == 0) && (am_header->rsvd3 == 0) && (am_header->rsvd5 == 0)))) { reserved_not_0("Async Msg"); } /* Draft 20, section 10.9.2 AsyncVCode * "AsyncVcode is a vendor specific detail code that is only * valid if the AsyncEvent field indicates a vendor specific * event. Otherwise, it is reserved." */ if (am_header->async_vcode != 0 && am_header->async_event != 255) { TRACE_ERROR ("AsyncVCode 0x%02x should be 0 when AsyncEvent is " "0x%02x\n", am_header->async_vcode, am_header->async_event); } /* Draft 20, section 10.9.3 LUN "The LUN field MUST be valid * if AsyncEvent is 0. Otherwise, this field is reserved." */ if (am_header->lun != 0 && am_header->async_event != 0) { TRACE_ERROR ("LUN 0x%016llx should be 0 when AsyncEvent is 0x%02x\n", am_header->lun, am_header->async_event); }#endif param1 = be16_to_cpu(am_header->parameter1); param2 = be16_to_cpu(am_header->parameter2); param3 = be16_to_cpu(am_header->parameter3); switch (am_header->async_event) { case 0: /* SCSI Asynchronous Event */ /* check for valid LUN, per section 9.9.3 quoted above */ lun = unpack_lun((__u8 *) & am_header->lun); if (!(related_session->lun_bits & (1 << lun))) { TRACE_ERROR("Invalid SCSI Asynch Event LUN %u\n", lun); } TRACE_ERROR("Unimplemented SCSI Asynchronous Event\n"); break; case 1: /* target requests Logout */#ifdef ISCSI_CHECK_PDU_FORMAT if (param1 != 0 || param2 != 0) { TRACE_ERROR ("Parameter1 0x%04x and Parameter2 0x%04x both should " "be 0 when AsyncEvent is 0x%02x\n", param1, param2, am_header->async_event); }#endif if (current_connection->connection_flags & SEND_NO_REPLY_TO_ASYNC_LOGOUT) { TRACE(TRACE_ISCSI, "Not replying to Async Logout " "request from target\n"); retval = 1; /* success */ } else if (!drive_logout(related_session, current_connection, LOGOUT_CLOSE_SESSION)) { TRACE_ERROR ("Unable to send Logout PDU requested by target\n"); } else { retval = 1; /* success */ } break; case 2: /* target dropping a specified connection */ /* NOTE we cannot just kill the connection, * since that might require this thread to kill * itself and then wait for itself to die, * which will not work. */ /* check that this CID actually matches an existing * connection id */ for (conn = related_session->connection_head; conn != NULL; conn = conn->next) { if (conn->connection_id == param1) { break; } } if (conn == NULL) { TRACE_ERROR ("Target dropping connection with nonexistant CID %u\n", param1); } else { TRACE(TRACE_ISCSI, "Target dropping connection with CID %u\n", param1); } retval = 1; /* success */ break; case 3: /* target dropping all connections in a session */ /* NOTE we cannot just kill the session, since * that might require this thread to kill itself * and then wait for itself to die, which will not work. */#ifdef ISCSI_CHECK_PDU_FORMAT if (param1 != 0) { TRACE_ERROR("Parameter1 0x%04x should be 0 " "when AsyncEvent is 0x%02x\n", param1, am_header->async_event); }#endif TRACE(TRACE_ISCSI, "Target dropping all connections in session\n"); retval = 1; /* success */ break; case 4: /* target requests Text negotiation */ if (unlikely(drive_text_negotiate(current_connection, related_session, 0, 0))) { TRACE_ERROR ("Unable to send Text PDU requested by target\n"); } else { retval = 1; /* success */ } break; case 255: /* vendor specific iSCSI Event */ TRACE(TRACE_ISCSI, "Ignoring vendor specific iSCSI Event, " "AsyncVcode 0x%02x\n", am_header->async_vcode); retval = 1; /* success */ break; default: TRACE_ERROR("Illegal AsyncEvent 0x%02x\n", am_header->async_event); retval = 1; /* success */ break; } /* switch */ TRACE(TRACE_ENTER_LEAVE, "Leave rx_async_msg, 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 task mgt response header, sets up the * task_mgt_response field in the command struct and wakes up the * initiator_abort function (called by SCSI Midlevel) waiting on the * task_mgt_sem semaphore. * Parameters: current_connection which is a ptr to the connection struct * where the Task Mgt. Header was received. * Return Value: >=0, on success (always) ****************************************************************************/static intrx_task_mgt_rsp(struct connection *current_connection, __u32 local_itt, struct command *related_command){ struct session *current_session; struct iscsi_targ_task_mgt_response *header; struct command *cmd; TRACE(TRACE_ENTER_LEAVE, "Enter rx_task_mgt_rsp, current_connection" " %p\n", current_connection); header = (struct iscsi_targ_task_mgt_response *) current_connection->rx_buf; TRACE(TRACE_DEBUG, "Got StatSN %u\n", ntohl(header->stat_sn)); /* Store the session pointer for future use - SAI */ current_session = current_connection->my_session;#ifdef ISCSI_CHECK_PDU_FORMAT /* Check if reserved fields are zero or not */ if (unlikely(!(((header->flags & ~F_BIT) == 0) && (header->rsvd1 == 0) && (header->rsvd2 == 0) && (header->rsvd4 == 0) && (header->rsvd5 == 0)))) { reserved_not_0("TM Response");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -