Files
haiku-beta6/src/add-ons/kernel/generic/scsi_periph/block.cpp
T

117 lines
3.1 KiB
C++
Raw Normal View History

2004-06-06 23:14:52 +00:00
/*
* Copyright 2004-2008, Haiku, Inc. All RightsReserved.
2007-05-10 14:13:37 +00:00
* Copyright 2002-2003, Thomas Kurschel. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
2004-06-06 23:14:52 +00:00
2007-05-10 14:13:37 +00:00
//! Handling of block device (currently, only a capacity check is provided)
2004-06-06 23:14:52 +00:00
#include "scsi_periph_int.h"
#include <string.h>
status_t
periph_check_capacity(scsi_periph_device_info *device, scsi_ccb *request)
{
2007-05-10 14:13:37 +00:00
scsi_res_read_capacity capacityResult;
2004-06-06 23:14:52 +00:00
scsi_cmd_read_capacity *cmd = (scsi_cmd_read_capacity *)request->cdb;
uint64 capacity;
2007-05-10 14:13:37 +00:00
uint32 blockSize;
2004-06-06 23:14:52 +00:00
status_t res;
SHOW_FLOW(3, "%p, %p", device, request);
// driver doesn't support capacity callback - seems to be no block
// device driver, so ignore
2004-06-06 23:14:52 +00:00
if (device->callbacks->set_capacity == NULL)
return B_OK;
request->flags = SCSI_DIR_IN;
request->data = (uint8*)&capacityResult;
2007-05-10 14:13:37 +00:00
request->data_length = sizeof(capacityResult);
request->cdb_length = sizeof(scsi_cmd_read_capacity);
2004-06-06 23:14:52 +00:00
request->timeout = device->std_timeout;
request->sort = -1;
request->sg_list = NULL;
memset(cmd, 0, sizeof(*cmd));
cmd->opcode = SCSI_OP_READ_CAPACITY;
// we don't set PMI (partial medium indicator) as we want the whole capacity;
// in this case, all other parameters must be zero
res = periph_safe_exec(device, request);
if (res == B_DEV_MEDIA_CHANGED) {
// in this case, the error handler has already called check_capacity
// recursively, so we ignore our (invalid) result
SHOW_FLOW0( 3, "ignore result because medium change" );
return B_DEV_MEDIA_CHANGED;
}
ACQUIRE_BEN(&device->mutex);
if (res == B_OK && request->data_resid == 0) {
2007-05-10 14:13:37 +00:00
capacity = B_BENDIAN_TO_HOST_INT32(capacityResult.lba);
2004-06-06 23:14:52 +00:00
2010-11-01 16:31:09 +00:00
if (capacity == UINT_MAX) {
RELEASE_BEN(&device->mutex);
2010-11-01 20:52:29 +00:00
scsi_cmd_read_capacity_long *cmd
= (scsi_cmd_read_capacity_long *)request->cdb;
2010-11-01 16:31:09 +00:00
scsi_res_read_capacity_long capacityLongResult;
request->data = (uint8*)&capacityLongResult;
request->data_length = sizeof(capacityLongResult);
request->cdb_length = sizeof(scsi_cmd_read_capacity_long);
memset(cmd, 0, sizeof(*cmd));
cmd->opcode = SCSI_OP_SERVICE_ACTION_IN;
cmd->service_action = SCSI_SAI_READ_CAPACITY_16;
res = periph_safe_exec(device, request);
ACQUIRE_BEN(&device->mutex);
if (res == B_OK && request->data_resid == 0) {
capacity = (((uint64)B_BENDIAN_TO_HOST_INT32(
capacityLongResult.lba >> 32)) << 32)
| B_BENDIAN_TO_HOST_INT32(capacityLongResult.lba);
} else
capacity = 0;
}
2004-06-06 23:14:52 +00:00
// the command returns the index of the _last_ block,
// i.e. the size is one larger
++capacity;
2007-05-10 14:13:37 +00:00
blockSize = B_BENDIAN_TO_HOST_INT32(capacityResult.block_size);
2004-06-06 23:14:52 +00:00
} else {
capacity = 0;
2007-05-10 14:13:37 +00:00
blockSize = 0;
2004-06-06 23:14:52 +00:00
}
2010-11-01 16:31:09 +00:00
SHOW_FLOW(3, "capacity = %lld, block_size = %ld", capacity, blockSize);
2004-06-06 23:14:52 +00:00
device->block_size = blockSize;
device->callbacks->set_capacity(device->periph_device,
2007-05-10 14:13:37 +00:00
capacity, blockSize);
2004-06-06 23:14:52 +00:00
/* device->byte2blk_shift = log2( device->block_size );
if( device->byte2blk_shift < 0 ) {
// this may be too restrictive...
device->capacity = -1;
return ERR_DEV_GENERAL;
}*/
RELEASE_BEN(&device->mutex);
SHOW_FLOW(3, "done (%s)", strerror(res));
return res;
}