Esempio n. 1
0
File: nop.c Progetto: djs55/libiscsi
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;
}
Esempio n. 2
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;
}
Esempio n. 3
0
File: nop.c Progetto: djs55/libiscsi
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;
}
Esempio n. 4
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;
}
Esempio n. 5
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;
}