Author: axeld Date: 2010-06-01 15:37:55 +0200 (Tue, 01 Jun 2010) New Revision: 36988 Changeset: http://dev.haiku-os.org/changeset/36988/haiku Modified: haiku/trunk/headers/private/drivers/scsi_periph.h haiku/trunk/src/add-ons/kernel/generic/scsi_periph/io.cpp haiku/trunk/src/add-ons/kernel/generic/scsi_periph/scsi_periph.cpp haiku/trunk/src/add-ons/kernel/generic/scsi_periph/scsi_periph_int.h Log: * Added a read_write() function to the scsi_periph module. * Internally, moved the contents of periph_io() into a static read_write() function, and use it from the new periph_read_write() as well. Modified: haiku/trunk/headers/private/drivers/scsi_periph.h =================================================================== --- haiku/trunk/headers/private/drivers/scsi_periph.h 2010-06-01 12:06:56 UTC (rev 36987) +++ haiku/trunk/headers/private/drivers/scsi_periph.h 2010-06-01 13:37:55 UTC (rev 36988) @@ -101,6 +101,9 @@ status_t (*handle_free)(scsi_periph_handle handle); // *** default implementation for block devices *** + status_t (*read_write)(scsi_periph_device_info *device, scsi_ccb *request, + uint64 offset, size_t numBlocks, physical_entry* vecs, size_t vecCount, + bool isWrite, size_t* _bytesTransferred); status_t (*io)(scsi_periph_device device, io_operation *operation, size_t *_bytesTransferred); Modified: haiku/trunk/src/add-ons/kernel/generic/scsi_periph/io.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/generic/scsi_periph/io.cpp 2010-06-01 12:06:56 UTC (rev 36987) +++ haiku/trunk/src/add-ons/kernel/generic/scsi_periph/io.cpp 2010-06-01 13:37:55 UTC (rev 36988) @@ -104,83 +104,24 @@ } -status_t -periph_ioctl(scsi_periph_handle_info *handle, int op, void *buffer, - size_t length) -{ - switch (op) { - case B_GET_MEDIA_STATUS: { - status_t res = B_OK; - - if (handle->device->removable) - res = periph_get_media_status(handle); - - SHOW_FLOW(2, "%s", strerror(res)); - - *(status_t *)buffer = res; - return B_OK; - } - - case B_SCSI_INQUIRY: - return inquiry(handle->device, (scsi_inquiry *)buffer); - - case B_SCSI_PREVENT_ALLOW: - return prevent_allow(handle->device, *(bool *)buffer); - - case B_RAW_DEVICE_COMMAND: - return raw_command(handle->device, (raw_device_command*)buffer); - - default: - if (handle->device->scsi->ioctl != NULL) { - return handle->device->scsi->ioctl(handle->device->scsi_device, - op, buffer, length); - } - - SHOW_ERROR(4, "Unknown ioctl: %x", op); - return B_BAD_VALUE; - } -} - - -/*! Kernel daemon - once in a minute, it sets a flag so that the next command - is executed ordered; this way, we avoid starvation of SCSI commands inside - the SCSI queuing system - the ordered command waits for all previous - commands and thus no command can starve longer then a minute -*/ -void -periph_sync_queue_daemon(void *arg, int iteration) -{ - scsi_periph_device_info *device = (scsi_periph_device_info *)arg; - - SHOW_FLOW0(3, "Setting ordered flag for next R/W access"); - atomic_or(&device->next_tag_action, SCSI_ORDERED_QTAG); -} - - /*! Universal read/write function */ -status_t -periph_io(scsi_periph_device_info *device, io_operation *operation, +static status_t +read_write(scsi_periph_device_info *device, scsi_ccb *request, + io_operation *operation, uint64 offset, size_t originalNumBlocks, + physical_entry* vecs, size_t vecCount, bool isWrite, size_t* _bytesTransferred) { uint32 blockSize = device->block_size; - size_t numBlocks = operation->Length() / blockSize; - uint32 pos = operation->Offset() / blockSize; - scsi_ccb *request; + size_t numBlocks = originalNumBlocks; + uint32 pos = offset; err_res res; int retries = 0; - int err; - // don't test rw10_enabled restrictions - this flag may get changed - request = device->scsi->alloc_ccb(device->scsi_device); - - if (request == NULL) - return B_NO_MEMORY; - do { size_t numBytes; - bool is_rw10; + bool isReadWrite10; - request->flags = operation->IsWrite() ? SCSI_DIR_OUT : SCSI_DIR_IN; + request->flags = isWrite ? SCSI_DIR_OUT : SCSI_DIR_IN; // make sure we avoid 10 byte commands if they aren't supported if (!device->rw10_enabled || device->preferred_ccb_size == 6) { @@ -190,10 +131,8 @@ numBlocks = 0x100; // no way to break the 21 bit address limit - if (pos > 0x200000) { - err = B_BAD_VALUE; - goto abort; - } + if (pos > 0x200000) + return B_BAD_VALUE; // don't allow transfer cross the 24 bit address limit // (I'm not sure whether this is allowed, but this way we @@ -203,13 +142,13 @@ } numBytes = numBlocks * blockSize; - if (numBytes != operation->Length()) + if (numBlocks != originalNumBlocks) panic("I/O operation would need to be cut."); request->data = NULL; - request->sg_list = (physical_entry*)operation->Vecs(); + request->sg_list = vecs; request->data_length = numBytes; - request->sg_count = operation->VecCount(); + request->sg_count = vecCount; request->io_operation = operation; request->sort = pos; request->timeout = device->std_timeout; @@ -223,11 +162,10 @@ if (pos + numBlocks < 0x200000 && numBlocks <= 0x100) { scsi_cmd_rw_6 *cmd = (scsi_cmd_rw_6 *)request->cdb; - is_rw10 = false; + isReadWrite10 = false; memset(cmd, 0, sizeof(*cmd)); - cmd->opcode = operation->IsWrite() - ? SCSI_OP_WRITE_6 : SCSI_OP_READ_6; + cmd->opcode = isWrite ? SCSI_OP_WRITE_6 : SCSI_OP_READ_6; cmd->high_lba = (pos >> 16) & 0x1f; cmd->mid_lba = (pos >> 8) & 0xff; cmd->low_lba = pos & 0xff; @@ -237,11 +175,10 @@ } else { scsi_cmd_rw_10 *cmd = (scsi_cmd_rw_10 *)request->cdb; - is_rw10 = true; + isReadWrite10 = true; memset(cmd, 0, sizeof(*cmd)); - cmd->opcode = operation->IsWrite() - ? SCSI_OP_WRITE_10 : SCSI_OP_READ_10; + cmd->opcode = isWrite ? SCSI_OP_WRITE_10 : SCSI_OP_READ_10; cmd->relative_address = 0; cmd->force_unit_access = 0; cmd->disable_page_out = 0; @@ -251,12 +188,11 @@ request->cdb_length = sizeof(*cmd); } - // last chance to detect errors that occured during concurrent accesses - err = 0; // TODO: handle->pending_error; + // TODO: last chance to detect errors that occured during concurrent accesses + //status_t status = handle->pending_error; + //if (status != B_OK) + // return status; - if (err) - goto abort; - device->scsi->async_io(request); acquire_sem(request->completion_sem); @@ -280,7 +216,7 @@ case err_act_invalid_req: // if this was a 10 byte command, the device probably doesn't // support them, so disable them and retry - if (is_rw10) { + if (isReadWrite10) { atomic_and(&device->rw10_enabled, 0); res.action = err_act_retry; } else @@ -290,17 +226,98 @@ } while ((res.action == err_act_retry && retries++ < 3) || (res.action == err_act_many_retries && retries++ < 30)); - device->scsi->free_ccb(request); - // peripheral layer only created "read" error, so we have to // map them to "write" errors if this was a write request - if (res.error_code == B_DEV_READ_ERROR && operation->IsWrite()) + if (res.error_code == B_DEV_READ_ERROR && isWrite) return B_DEV_WRITE_ERROR; return res.error_code; +} -abort: + +// #pragma mark - public functions + + +status_t +periph_ioctl(scsi_periph_handle_info *handle, int op, void *buffer, + size_t length) +{ + switch (op) { + case B_GET_MEDIA_STATUS: { + status_t res = B_OK; + + if (handle->device->removable) + res = periph_get_media_status(handle); + + SHOW_FLOW(2, "%s", strerror(res)); + + *(status_t *)buffer = res; + return B_OK; + } + + case B_SCSI_INQUIRY: + return inquiry(handle->device, (scsi_inquiry *)buffer); + + case B_SCSI_PREVENT_ALLOW: + return prevent_allow(handle->device, *(bool *)buffer); + + case B_RAW_DEVICE_COMMAND: + return raw_command(handle->device, (raw_device_command*)buffer); + + default: + if (handle->device->scsi->ioctl != NULL) { + return handle->device->scsi->ioctl(handle->device->scsi_device, + op, buffer, length); + } + + SHOW_ERROR(4, "Unknown ioctl: %x", op); + return B_BAD_VALUE; + } +} + + +/*! Kernel daemon - once in a minute, it sets a flag so that the next command + is executed ordered; this way, we avoid starvation of SCSI commands inside + the SCSI queuing system - the ordered command waits for all previous + commands and thus no command can starve longer then a minute +*/ +void +periph_sync_queue_daemon(void *arg, int iteration) +{ + scsi_periph_device_info *device = (scsi_periph_device_info *)arg; + + SHOW_FLOW0(3, "Setting ordered flag for next R/W access"); + atomic_or(&device->next_tag_action, SCSI_ORDERED_QTAG); +} + + +status_t +periph_read_write(scsi_periph_device_info *device, scsi_ccb *request, + uint64 offset, size_t numBlocks, physical_entry* vecs, size_t vecCount, + bool isWrite, size_t* _bytesTransferred) +{ + return read_write(device, request, NULL, offset, numBlocks, vecs, vecCount, + isWrite, _bytesTransferred); +} + + +status_t +periph_io(scsi_periph_device_info *device, io_operation *operation, + size_t* _bytesTransferred) +{ + const uint32 blockSize = device->block_size; + + // don't test rw10_enabled restrictions - this flag may get changed + scsi_ccb *request = device->scsi->alloc_ccb(device->scsi_device); + if (request == NULL) + return B_NO_MEMORY; + + status_t status = read_write(device, request, operation, + operation->Offset() / blockSize, operation->Length() / blockSize, + (physical_entry *)operation->Vecs(), operation->VecCount(), + operation->IsWrite(), _bytesTransferred); + device->scsi->free_ccb(request); - return err; + return status; } Modified: haiku/trunk/src/add-ons/kernel/generic/scsi_periph/scsi_periph.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/generic/scsi_periph/scsi_periph.cpp 2010-06-01 12:06:56 UTC (rev 36987) +++ haiku/trunk/src/add-ons/kernel/generic/scsi_periph/scsi_periph.cpp 2010-06-01 13:37:55 UTC (rev 36988) @@ -131,6 +131,7 @@ periph_handle_close, periph_handle_free, + periph_read_write, periph_io, periph_ioctl, periph_check_capacity, Modified: haiku/trunk/src/add-ons/kernel/generic/scsi_periph/scsi_periph_int.h =================================================================== --- haiku/trunk/src/add-ons/kernel/generic/scsi_periph/scsi_periph_int.h 2010-06-01 12:06:56 UTC (rev 36987) +++ haiku/trunk/src/add-ons/kernel/generic/scsi_periph/scsi_periph_int.h 2010-06-01 13:37:55 UTC (rev 36988) @@ -91,6 +91,9 @@ // io.c +status_t periph_read_write(scsi_periph_device_info *device, scsi_ccb *request, + uint64 offset, size_t numBlocks, physical_entry* vecs, size_t vecCount, + bool isWrite, size_t* _bytesTransferred); status_t periph_io(scsi_periph_device_info* device, io_operation* operation, size_t *_bytesTransferred); status_t periph_ioctl(scsi_periph_handle_info *handle, int op,