📄 initiator_utilities.c
字号:
__u32 lun; slength = related_command->SCpnt->request_bufflen; TRACE(TRACE_DEBUG, "completed read capacity, slength %d, missing %d\n", slength, missing); if (missing > 0) slength -= missing; if (slength >= 8) {#ifdef K26 lun = related_command->SCpnt->device->lun;#else lun = related_command->SCpnt->lun;#endif sess->capacity_lba[lun] = ntohl( *(__u32 *)related_command->SCpnt->request_buffer); sess->capacity_len[lun] = ntohl( *(__u32 *)(related_command->SCpnt->request_buffer + 4)); printk("capacity for lun %u [%u, %u]\n", lun, sess->capacity_lba[lun], sess->capacity_len[lun]); }}/* we just successfully completed a read block limits command */voidsave_limits(struct session *sess, struct command *related_command, int missing){ int slength; __u32 lun; slength = related_command->SCpnt->request_bufflen; TRACE(TRACE_DEBUG, "completed read block limits, slength %d, " "missing %d\n", slength, missing); if (missing > 0) slength -= missing; if (slength >= 6) {#ifdef K26 lun = related_command->SCpnt->device->lun;#else lun = related_command->SCpnt->lun;#endif sess->limit_max[lun] = ntohl( (*(__u32 *)related_command->SCpnt->request_buffer)) & MASK_24_BITS; sess->limit_min[lun] = ntohs( (*(__u16 *)(related_command->SCpnt->request_buffer + 4))) & MASK_24_BITS; printk("block limits for lun %u [%u, %u]\n", lun, sess->limit_min[lun], sess->limit_max[lun]); }}intsend_data_ack_snack(struct connection *current_connection, struct command *related_command, __u32 increment){ int retval = 1; struct init_error_rec err_rec; struct iscsi_targ_scsi_data_in *header; /* time to send a snack because of previous error */ TRACE(TRACE_ISCSI, "Sending SNACK type %u, ITT %u, offset %u, begrun %u, " "runlen %u\n", DATA_R2T_SNACK, related_command->init_task_tag, related_command->cmd_error_offset, related_command->cmd_error_begrun, related_command->cmd_error_runlen); related_command->cmd_error_state = CMD_USING_SNACK; /* save fields from current command so they can be restored after * retransmission (only when current command is DataIn with A bit set) */ if (increment == 0) { /* cause by a DataIn with A bit set, save stuff */ related_command->abit_offset = related_command->data_offset; related_command->abit_in_sn = related_command->data_in_sn; header = (struct iscsi_targ_scsi_data_in *) current_connection->rx_buf; related_command->abit_ttt = header->target_xfer_tag; related_command->abit_lun = header->lun; } /* reset "normal" fields in current command to handle retransmission */ related_command->data_offset = related_command->cmd_error_offset; related_command->data_in_sn = related_command->cmd_error_begrun; /* MAYBE undo previous increment of StatSN as we do not want to * acknowledge correct receipt of all the DataIns yet. * Save the increment so we can apply it again when all DataIns are ok */ current_connection->exp_stat_sn -= increment; current_connection->increment = increment; err_rec.curr_conn = current_connection; err_rec.related_cmd = related_command; err_rec.err_type = SEQUENCE_ERR; if (!init_send_snack(&err_rec, related_command->cmd_error_begrun, related_command->cmd_error_runlen, DATA_R2T_SNACK)) { /* SNACK not sent for some reason, escalate to session recovry*/ retval = init_session_recovery(&err_rec); } return retval;}/* * executed only by rx thread. * process the common parts of a SCSIResponse PDU and a DataIn * PDU with the S-bit set ("phase collapse") * the current_session->sess_lock MUST be held by the calling thread. * Returns >0 on success, session lock is locked * =0 on failure, session lock is locked * <0 on failure, session lock is NOT locked */intdo_scsi_response(struct connection *current_connection, struct command *related_command, struct iscsi_targ_scsi_rsp *header, int received, __u8 * buffer){ int missing, slength, retval = 1; __u32 residual; TRACE(TRACE_ENTER_LEAVE, "Enter do_scsi_response\n"); if (unlikely(related_command->cmd_error_state == CMD_NEEDS_SNACK)) { /* time to send a snack because of previous error */ retval = send_data_ack_snack(current_connection, related_command, 1); goto out; } residual = ntohl(header->resid); /* see if initiator and target agree on amount of data transfered */ if (unlikely(related_command->r2t_range_list.next != NULL)) { /* Command with DataSequenceInOrder==No */ /* expected range of any command is: offset=0, limit=bufflen */ related_command->r2t_range_list.offset = 0; related_command->r2t_range_list.limit = related_command->SCpnt->request_bufflen; missing = check_range_list_complete(&related_command->r2t_range_list); } else { /* Command with DataSequenceInOrder==Yes */ missing = related_command->SCpnt->request_bufflen - related_command->data_offset; } if (unlikely(header->flags & U_BIT)) { /* U bit is set, indicating underflow, check residual count */ TRACE(TRACE_ISCSI, "Underflow: Residual count %u\n", residual); if (missing != residual && !(header->status & STATUS_MASK)) { TRACE_ERROR("Underflow Residual count %u doesn't match " "expected %d\n", residual, missing); } } else if (unlikely(header->flags & O_BIT)) { /* O bit is set, indicating overflow, check residual count */ TRACE(TRACE_ISCSI, "Overflow: Residual count %u\n", residual); if (!(header->status & STATUS_MASK)) { if (missing != 0) { TRACE_ERROR ("Overflow bit set, but still missing %d " "bytes\n", missing); } else if (residual == 0) { TRACE_ERROR ("Overflow bit set, but Residual count is 0\n"); } } } else if (unlikely(residual != 0)) { TRACE_ERROR ("Neither Overflow nor Underflow set, but Residual count is" " %u\n", residual); } /* pass the final status back up to the SCSI Mid-level * the "result" field of the command contains 4 independent bytes: * byte 0: status byte returned from the device itself in bits 1 thru 5 * byte 1: status returned from the host adapter (always 0 for us) * byte 2: status returned by the low-level driver * byte 3: "simply the message byte that comes back" whatever that is. * * The byte 2 errors are defined in /usr/src/linux/drivers/scsi/scsi.h * and are symbols of the form DID_xxx. DID_OK is conveniently 0. */ related_command->SCpnt->result = header->status; if (unlikely(header->status & STATUS_MASK)) { TRACE_ERROR("%s scsi response error from target, " "status 0x%02x\n", current->comm, header->status); /* mark this as an internal error of some sort */ related_command->SCpnt->result |= (DID_ERROR << 16); /* we will never transmit anything else for this command */ related_command->cmd_state |= CMD_STATE_TXDONE; /* Linux defines CHECK_CONDITION as 0x01, * and SAM-2 requires it to be 0x02 (see Draft 20, * Section 10.4.2). This is because Linux does not * consider the low order bit to be part of the status, * since SAM-2 requires that bit to be 0. * The status_byte() macro in linux/drivers/scsi/scsi.h * handles this. See also linux/include/scsi/scsi.h. */ if (likely(status_byte(header->status) == CHECK_CONDITION)) { /* Draft 20, Section 10.4.7 Data Segment - * Sense and Response Data Segment "iSCSI * targets MUST support and enable autosense. * If Status is CHECK CONDITION (0x02), * then the Data Segment MUST contain sense * data for the failed command." */ slength = 0; if (received <= 0 || buffer == NULL) { TRACE_ERROR ("CHECK CONDITION but no sense data\n"); } else { if (received < 2) { TRACE_ERROR("%d data bytes not enough " "to contain sense length\n", received); } else { /* big-endian 16-bits */ slength = (buffer[0] << 8) + buffer[1]; if (slength > received - 2) { TRACE_ERROR("%d sense data " "bytes but only %d actually " "received\n", slength, received - 2); slength = received - 2; } if (slength > SCSI_SENSE_BUFFERSIZE) { if (TRACE_TEST(TRACE_ISCSI)) { TRACE_WARNING("received " "%d sense data bytes but " "midlevel buffer holds " "%d\n", slength, SCSI_SENSE_BUFFERSIZE); } slength = SCSI_SENSE_BUFFERSIZE; } if (slength > 0) { /* have some sense data, * copy it into buffer */ memcpy(related_command->SCpnt-> sense_buffer, &buffer[2], slength); /* Note -- we expect the * midlevel to have zeroed the * sense buffer before calling * queuecommand(). Therefore, * we do not have to zero the * unfilled part of the buf * (and do not have to do * anything if sense data is * missing completely). */ /* mark that driver sense * data is present */ related_command->SCpnt-> result |= (DRIVER_SENSE << 24); /* print the sense data */ printk("%d bytes of sense " "data\n", slength); dump_buffer(buffer + 2, slength); } } } } } else if (related_command->header_opcode == ISCSI_INIT_SCSI_CMND && related_command->SCpnt != NULL && related_command->SCpnt->use_sg == 0) { if (related_command->iscsi_cmd.cdb[0] == INQUIRY) save_inquiry(current_connection->my_session, related_command, missing); else if (related_command->iscsi_cmd.cdb[0] == READ_CAPACITY) save_capacity(current_connection->my_session, related_command, missing); else if (related_command->iscsi_cmd.cdb[0] == READ_BLOCK_LIMITS) save_limits(current_connection->my_session, related_command, missing); } /* no errors on this command or done with recovery */ related_command->cmd_state |= CMD_STATE_RXDONE; free_pending_command(related_command, current_connection);out: TRACE(TRACE_ENTER_LEAVE, "Leave do_scsi_response, retval %d\n", retval); return retval;}/* * executed by init_recovery thread, scsi midlevel process. * the session->sess_lock MUST be held by the calling process/thread. * Called to allocate space for a struct command and then initialize it. * Returns pointer to newly allocated and initialized command if all ok, * else NULL. */struct command *setup_command(struct scsi_cmnd * Cmnd, struct connection *conn){ struct command *new_command; struct session *sess = conn->my_session; struct list_head *lptr; TRACE(TRACE_ENTER_LEAVE, "Enter setup_command\n"); if (unlikely(list_empty(&sess->free_commands))) { TRACE_WARNING("setup_command allocating %d bytes for " "%uth command in session\n", sizeof(struct command), sess->n_commands_alloced+1); new_command = (struct command *) my_kmalloc(sizeof(struct command), "command"); if (unlikely(new_command == NULL)) goto out; sess->n_commands_alloced++; } else { lptr = sess->free_commands.next; list_del(lptr); new_command = list_entry(lptr, struct command, link); } /* setup the new command struct (most fields 0/NULL) * * Draft 20, Section 10.7.5 DataSN "For input (read) or * bidirectional Data-In PDUs, the DataSN is the * input PDU number within the data transfer for the * command identified by the Initiator Task Tag." * * Draft 20, Section 10.8.2 R2TSN * "R2TSN is the R2T PDU input PDU number within * the command identified by the Initiator Task Tag." */ /* zero out just the first part of the struct command */ memset(new_command, 0, (long)&((struct command *)NULL)->SCpnt); new_command->SCpnt = Cmnd; INIT_LIST_HEAD(&new_command->r2t_cookies); /* set up the transmit i/o vector for the iscsi header */ setup_header_iovec(conn, new_command);#ifdef K26 new_command->pindex = 0; new_command->padding = 0;#endifout: TRACE(TRACE_ENTER_LEAVE, "Leave setup_command, command %p\n", new_command); return new_command;}/* * executed only by rx thread. * called only from recv_data_in_data() * There is a Data Digest err, handle appropriately - SAI */static int __attribute__ ((no_instrument_function))recv_data_in_error (struct connection *current_connection, struct command *related_command, struct iscsi_targ_scsi_data_in *data_in_header, __u32 *size){ int received; struct init_error_rec err_rec;#ifdef ISCSI_STATS current_connection->my_session->sess_stats->iscsi_ssn_digest_err++;#endif err_rec.curr_conn = current_connection; err_rec.related_cmd = related_command; err_rec.err_type = PAYLOAD_DIGERR; received = init_do_error_recovery(&err_rec); if (unlikely(received <= 0)) goto out; /* force the expected data offset to the one received in order * to avoid a cascade of error messages */ if (likely(related_command != NULL)) { related_command->data_offset += *size; TRACE(TRACE_DEBUG, "Bump offset by %d, received %d\n", *size, received); /* do not count this data as having been received yet */ *size = 0; }out: return received;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -