2004-06-06 23:14:52 +00:00
|
|
|
/*
|
2008-08-05 21:11:51 +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
|
2008-08-05 21:11:51 +00:00
|
|
|
// 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;
|
|
|
|
|
|
2008-08-05 21:11:51 +00:00
|
|
|
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
|
|
|
|
2008-08-05 21:11:51 +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;
|
|
|
|
|
}
|
|
|
|
|
|