int iscsi_nop_out_async(struct iscsi_context *iscsi, iscsi_command_cb cb, unsigned char *data, int len, void *private_data) { struct iscsi_pdu *pdu; if (iscsi->is_loggedin == 0) { iscsi_set_error(iscsi, "trying to send nop-out while not " "logged in"); return -1; } pdu = iscsi_allocate_pdu(iscsi, ISCSI_PDU_NOP_OUT, ISCSI_PDU_NOP_IN); if (pdu == NULL) { iscsi_set_error(iscsi, "Failed to allocate nop-out pdu"); return -1; } /* immediate flag */ iscsi_pdu_set_immediate(pdu); /* flags */ iscsi_pdu_set_pduflags(pdu, 0x80); /* ttt */ iscsi_pdu_set_ttt(pdu, 0xffffffff); /* lun */ iscsi_pdu_set_lun(pdu, 0); /* cmdsn is not increased if Immediate delivery*/ iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn); pdu->cmdsn = iscsi->cmdsn; /* exp statsn */ iscsi_pdu_set_expstatsn(pdu, iscsi->statsn+1); pdu->callback = cb; pdu->private_data = private_data; if (iscsi_pdu_add_data(iscsi, pdu, data, len) != 0) { iscsi_set_error(iscsi, "Failed to add outdata to nop-out"); iscsi_free_pdu(iscsi, pdu); return -1; } if (iscsi_queue_pdu(iscsi, pdu) != 0) { iscsi_set_error(iscsi, "failed to queue iscsi nop-out pdu"); iscsi_free_pdu(iscsi, pdu); return -1; } return 0; }
int iscsi_logout_async(struct iscsi_context *iscsi, iscsi_command_cb cb, void *private_data) { struct iscsi_pdu *pdu; iscsi->login_attempts = 0; if (iscsi->is_loggedin == 0) { iscsi_set_error(iscsi, "Trying to logout while not logged in."); return -1; } pdu = iscsi_allocate_pdu(iscsi, ISCSI_PDU_LOGOUT_REQUEST, ISCSI_PDU_LOGOUT_RESPONSE); if (pdu == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to allocate " "logout pdu."); return -1; } /* logout request has the immediate flag set */ iscsi_pdu_set_immediate(pdu); /* flags : close the session */ iscsi_pdu_set_pduflags(pdu, 0x80); /* cmdsn is not increased if Immediate delivery*/ iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn); pdu->cmdsn = iscsi->cmdsn; /* exp statsn */ iscsi_pdu_set_expstatsn(pdu, iscsi->statsn+1); pdu->callback = cb; pdu->private_data = private_data; if (iscsi_queue_pdu(iscsi, pdu) != 0) { iscsi_set_error(iscsi, "Out-of-memory: failed to queue iscsi " "logout pdu."); iscsi_free_pdu(iscsi, pdu); return -1; } return 0; }
int iscsi_send_target_nop_out(struct iscsi_context *iscsi, uint32_t ttt) { struct iscsi_pdu *pdu; pdu = iscsi_allocate_pdu_with_itt_flags(iscsi, ISCSI_PDU_NOP_OUT, ISCSI_PDU_NO_PDU, 0xffffffff,ISCSI_PDU_DELETE_WHEN_SENT|ISCSI_PDU_NO_CALLBACK); if (pdu == NULL) { iscsi_set_error(iscsi, "Failed to allocate nop-out pdu"); return -1; } /* immediate flag */ iscsi_pdu_set_immediate(pdu); /* flags */ iscsi_pdu_set_pduflags(pdu, 0x80); /* ttt */ iscsi_pdu_set_ttt(pdu, ttt); /* lun */ iscsi_pdu_set_lun(pdu, 0); /* cmdsn is not increased if Immediate delivery*/ iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn); pdu->cmdsn = iscsi->cmdsn; /* exp statsn */ iscsi_pdu_set_expstatsn(pdu, iscsi->statsn+1); if (iscsi_queue_pdu(iscsi, pdu) != 0) { iscsi_set_error(iscsi, "failed to queue iscsi nop-out pdu"); iscsi_free_pdu(iscsi, pdu); return -1; } return 0; }
static int iscsi_write_to_socket(struct iscsi_context *iscsi) { ssize_t count; size_t total; struct iscsi_pdu *pdu; static char padding_buf[3]; int socket_flags = 0; #ifdef MSG_NOSIGNAL socket_flags |= MSG_NOSIGNAL; #elif SO_NOSIGPIPE socket_flags |= SO_NOSIGPIPE; #endif if (iscsi->fd == -1) { iscsi_set_error(iscsi, "trying to write but not connected"); return -1; } while (iscsi->outqueue != NULL || iscsi->outqueue_current != NULL) { if (iscsi->outqueue_current == NULL) { if (iscsi->is_corked) { /* connection is corked we are not allowed to send * additional PDUs */ ISCSI_LOG(iscsi, 6, "iscsi_write_to_socket: socket is corked"); return 0; } if (iscsi_serial32_compare(iscsi->outqueue->cmdsn, iscsi->maxcmdsn) > 0 && !(iscsi->outqueue->outdata.data[0] & ISCSI_PDU_IMMEDIATE)) { /* stop sending for non-immediate PDUs. maxcmdsn is reached */ ISCSI_LOG(iscsi, 6, "iscsi_write_to_socket: maxcmdsn reached (outqueue[0]->cmdsnd %08x > maxcmdsn %08x)", iscsi->outqueue->cmdsn, iscsi->maxcmdsn); return 0; } /* pop first element of the outqueue */ if (iscsi_serial32_compare(iscsi->outqueue->cmdsn, iscsi->expcmdsn) < 0 && (iscsi->outqueue->outdata.data[0] & 0x3f) != ISCSI_PDU_DATA_OUT) { iscsi_set_error(iscsi, "iscsi_write_to_socket: outqueue[0]->cmdsn < expcmdsn (%08x < %08x) opcode %02x", iscsi->outqueue->cmdsn, iscsi->expcmdsn, iscsi->outqueue->outdata.data[0] & 0x3f); return -1; } iscsi->outqueue_current = iscsi->outqueue; /* set exp statsn */ iscsi_pdu_set_expstatsn(iscsi->outqueue_current, iscsi->statsn + 1); ISCSI_LIST_REMOVE(&iscsi->outqueue, iscsi->outqueue_current); if (!(iscsi->outqueue_current->flags & ISCSI_PDU_DELETE_WHEN_SENT)) { /* we have to add the pdu to the waitqueue already here since the storage might sent a R2T as soon as it has received the header. if we sent immediate data in a cmd PDU the R2T might get lost otherwise. */ ISCSI_LIST_ADD_END(&iscsi->waitpdu, iscsi->outqueue_current); } } pdu = iscsi->outqueue_current; pdu->outdata.size = (pdu->outdata.size + 3) & 0xfffffffc; /* Write header and any immediate data */ if (pdu->outdata_written < pdu->outdata.size) { count = send(iscsi->fd, pdu->outdata.data + pdu->outdata_written, pdu->outdata.size - pdu->outdata_written, socket_flags); if (count == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { return 0; } iscsi_set_error(iscsi, "Error when writing to " "socket :%d", errno); return -1; } pdu->outdata_written += count; } /* if we havent written the full header yet. */ if (pdu->outdata_written != pdu->outdata.size) { return 0; } /* Write any iovectors that might have been passed to us */ while (pdu->payload_written < pdu->payload_len) { struct scsi_iovector* iovector_out; iovector_out = iscsi_get_scsi_task_iovector_out(iscsi, pdu); if (iovector_out == NULL) { iscsi_set_error(iscsi, "Can't find iovector data for DATA-OUT"); return -1; } count = iscsi_iovector_readv_writev(iscsi, iovector_out, pdu->payload_offset + pdu->payload_written, pdu->payload_len - pdu->payload_written, 1); if (count == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { return 0; } iscsi_set_error(iscsi, "Error when writing to " "socket :%d %s", errno, iscsi_get_error(iscsi)); return -1; } pdu->payload_written += count; } total = pdu->payload_len; total = (total + 3) & 0xfffffffc; /* Write padding */ if (pdu->payload_written < total) { count = send(iscsi->fd, padding_buf, total - pdu->payload_written, socket_flags); if (count == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { return 0; } iscsi_set_error(iscsi, "Error when writing to " "socket :%d", errno); return -1; } pdu->payload_written += count; } /* if we havent written the full padding yet. */ if (pdu->payload_written != total) { return 0; } if (pdu->flags & ISCSI_PDU_CORK_WHEN_SENT) { iscsi->is_corked = 1; } if (pdu->flags & ISCSI_PDU_DELETE_WHEN_SENT) { iscsi->t->free_pdu(iscsi, pdu); } iscsi->outqueue_current = NULL; } return 0; }
static int iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun, struct scsi_task *task, iscsi_command_cb cb, struct iscsi_data *data, void *private_data) { struct iscsi_pdu *pdu; struct iscsi_scsi_cbdata *scsi_cbdata; int flags; if (iscsi == NULL) { printf("trying to send command on NULL context\n"); scsi_free_scsi_task(task); return -1; } if (iscsi->session_type != ISCSI_SESSION_NORMAL) { printf("Trying to send command on discovery session\n"); scsi_free_scsi_task(task); return -2; } if (iscsi->is_loggedin == 0) { printf("Trying to send command while not logged in\n"); scsi_free_scsi_task(task); return -3; } scsi_cbdata = malloc(sizeof(struct iscsi_scsi_cbdata)); if (scsi_cbdata == NULL) { printf("failed to allocate scsi cbdata\n"); scsi_free_scsi_task(task); return -4; } bzero(scsi_cbdata, sizeof(struct iscsi_scsi_cbdata)); scsi_cbdata->task = task; scsi_cbdata->callback = cb; scsi_cbdata->private_data = private_data; pdu = iscsi_allocate_pdu(iscsi, ISCSI_PDU_SCSI_REQUEST, ISCSI_PDU_SCSI_RESPONSE); if (pdu == NULL) { printf("Failed to allocate text pdu\n"); iscsi_free_scsi_cbdata(scsi_cbdata); return -5; } pdu->scsi_cbdata = scsi_cbdata; /* flags */ flags = ISCSI_PDU_SCSI_FINAL|ISCSI_PDU_SCSI_ATTR_SIMPLE; switch (task->xfer_dir) { case SCSI_XFER_NONE: break; case SCSI_XFER_READ: flags |= ISCSI_PDU_SCSI_READ; break; case SCSI_XFER_WRITE: flags |= ISCSI_PDU_SCSI_WRITE; if (data == NULL) { printf("DATA-OUT command but data == NULL\n"); iscsi_free_pdu(iscsi, pdu); return -5; } if (data->size != task->expxferlen) { printf("data size:%d is not same as expected data transfer length:%d\n", data->size, task->expxferlen); iscsi_free_pdu(iscsi, pdu); return -7; } if (iscsi_pdu_add_data(iscsi, pdu, data->data, data->size) != 0) { printf("Failed to add outdata to the pdu\n"); iscsi_free_pdu(iscsi, pdu); return -6; } break; } iscsi_pdu_set_pduflags(pdu, flags); /* lun */ iscsi_pdu_set_lun(pdu, lun); /* expxferlen */ iscsi_pdu_set_expxferlen(pdu, task->expxferlen); /* cmdsn */ iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn); pdu->cmdsn = iscsi->cmdsn; iscsi->cmdsn++; /* exp statsn */ iscsi_pdu_set_expstatsn(pdu, iscsi->statsn+1); /* cdb */ iscsi_pdu_set_cdb(pdu, task); pdu->callback = iscsi_scsi_response_cb; pdu->private_data = scsi_cbdata; if (iscsi_queue_pdu(iscsi, pdu) != 0) { printf("failed to queue iscsi scsi pdu\n"); iscsi_free_pdu(iscsi, pdu); return -6; } return 0; }