Example #1
0
bool scsi_send_cmd(size_t data_length, bool reading, int sg_size, uint8 **sg_ptr, uint32 *sg_len, uint16 *stat, uint32 timeout)
{
	static int pack_id = 0;

	// Check if buffer is large enough, allocate new buffer if needed
	if (!try_buffer(data_length)) {
		char str[256];
		sprintf(str, GetString(STR_SCSI_BUFFER_ERR), data_length);
		ErrorAlert(str);
		return false;
	}

	// Process S/G table when writing
	if (!reading) {
		D(bug(" writing to buffer\n"));
		uint8 *buffer_ptr = buffer + sizeof(sg_header) + the_cmd_len;
		for (int i=0; i<sg_size; i++) {
			uint32 len = sg_len[i];
			D(bug("  %d bytes from %08lx\n", len, sg_ptr[i]));
			memcpy(buffer_ptr, sg_ptr[i], len);
			buffer_ptr += len;
		}
	}

	// Request Sense and autosense data valid?
	sg_header *h = (sg_header *)buffer;
	int res;
	if (reading && the_cmd[0] == 0x03 && (h->target_status & DRIVER_SENSE)) {

		// Yes, fake command
		D(bug(" autosense\n"));
		memcpy(buffer + sizeof(sg_header), h->sense_buffer, 16);
		h->target_status &= ~DRIVER_SENSE;
		res = 0;
		*stat = 0;

	} else {

		// No, send regular command
		if (timeout) {
			int to = timeout * HZ / 60;
			ioctl(fd, SG_SET_TIMEOUT, &to);
		}
		ioctl(fd, SG_NEXT_CMD_LEN, &the_cmd_len);

		D(bug(" sending command, length %d\n", data_length));

		int request_size, reply_size;
		if (reading) {
			h->pack_len = request_size = sizeof(sg_header) + the_cmd_len;
			h->reply_len = reply_size = sizeof(sg_header) + data_length;
		} else {
			h->pack_len = request_size = sizeof(sg_header) + the_cmd_len + data_length;
			h->reply_len = reply_size = sizeof(sg_header);
		}
		h->pack_id = pack_id++;
		h->result = 0;
		h->twelve_byte = (the_cmd_len == 12);
		h->target_status = 0;
		h->host_status = 0;
		h->driver_status = 0;
		h->other_flags = 0;
		memcpy(buffer + sizeof(sg_header), the_cmd, the_cmd_len);

		res = write(fd, buffer, request_size);
		D(bug(" request sent, actual %d, result %d\n", res, h->result));
		if (res >= 0) {
			res = read(fd, buffer, reply_size);
			D(bug(" reply read, actual %d, result %d, status %02x\n", res, h->result, h->target_status << 1));
		}

		*stat = h->target_status << 1;
	}

	// Process S/G table when reading
	if (reading && h->result == 0) {
		D(bug(" reading from buffer\n"));
		uint8 *buffer_ptr = buffer + sizeof(sg_header);
		for (int i=0; i<sg_size; i++) {
			uint32 len = sg_len[i];
			D(bug("  %d bytes to %08lx\n", len, sg_ptr[i]));
			memcpy(sg_ptr[i], buffer_ptr, len);
			buffer_ptr += len;
		}
	}
	return res >= 0;
}
Example #2
0
bool scsi_send_cmd(size_t data_length, bool reading, int sg_size, uint8 **sg_ptr, uint32 *sg_len, uint16 *stat, uint32 timeout)
{
	// Bypass the buffer if there's only one S/G table entry
	bool do_direct_transfer = (sg_size == 1 && ((uint32)sg_ptr[0] & 1) == 0 && direct_transfers_supported);

	if (!do_direct_transfer) {

		// Check if buffer is large enough, allocate new buffer if needed
		if (!try_buffer(data_length)) {
			char str[256];
			sprintf(str, GetString(STR_SCSI_BUFFER_ERR), data_length);
			ErrorAlert(str);
			return false;
		}

		// Process S/G table when writing
		if (!reading) {
			D(bug(" writing to buffer\n"));
			uint8 *buffer_ptr = buffer;
			for (int i=0; i<sg_size; i++) {
				uint32 len = sg_len[i];
				D(bug("  %d bytes from %08lx\n", len, sg_ptr[i]));
				memcpy(buffer_ptr, sg_ptr[i], len);
				buffer_ptr += len;
			}
		}
	}

	// Request Sense and autosense data valid?
	BYTE res = 0;
	if (cmd_buffer[0] == 0x03 && scsi.scsi_SenseActual) {

		// Yes, fake command
		D(bug(" autosense\n"));
		memcpy(buffer, sense_buffer, scsi.scsi_SenseActual);
		scsi.scsi_Status = 0;
		do_direct_transfer = false;

	} else {

		// No, send regular command
		D(bug(" sending command, length %ld\n", data_length));
		if (do_direct_transfer) {
			scsi.scsi_Data = (UWORD *)sg_ptr[0];
			scsi.scsi_Length = sg_len[0];
		} else {
			scsi.scsi_Data = (UWORD *)buffer;
			scsi.scsi_Length = data_length;
		}
		scsi.scsi_Actual = 0;
		scsi.scsi_Flags = (reading ? SCSIF_READ : SCSIF_WRITE) | SCSIF_AUTOSENSE;
		scsi.scsi_SenseActual = 0;
		scsi.scsi_Status = 0;
		res = DoIO((struct IORequest *)io);
		D(bug(" command sent, res %d, status %d\n", res, scsi.scsi_Status));
		*stat = scsi.scsi_Status;
	}

	if (!do_direct_transfer) {

		// Process S/G table when reading
		if (reading && res == 0) {
			D(bug(" reading from buffer\n"));
			uint8 *buffer_ptr = buffer;
			for (int i=0; i<sg_size; i++) {
				uint32 len = sg_len[i];
				D(bug("  %d bytes to %08lx\n", len, sg_ptr[i]));
				memcpy(sg_ptr[i], buffer_ptr, len);
				buffer_ptr += len;
			}
		}
	}
	return res == 0;
}