scsi_periph: implemented VPD inquiry.

* declared block limits and logical block provisioning structs.
* based on SPC-4 and SBC-4 standards.
This commit is contained in:
Jérôme Duval 2014-04-09 20:35:26 +02:00
parent 91810926dc
commit 6fd00f80e8
2 changed files with 136 additions and 3 deletions

View File

@ -309,10 +309,28 @@ enum scsi_device_type {
};
// vital product data: pages
#define SCSI_PAGE_SUPPORTED_VPD 0x00 /* Supported VPD Pages */
#define SCSI_PAGE_USN 0x80 /* Unit serial number */
#define SCSI_PAGE_BLOCK_LIMITS 0xb0 /* Block limits */
#define SCSI_PAGE_BLOCK_DEVICE_CHARS 0xb1 /* Block device characteristics */
#define SCSI_PAGE_LB_PROVISIONING 0xb2 /* Logical block provisioning */
#define SCSI_PAGE_REFERRALS 0xb3 /* Referrals */
// vital product data: supported pages
typedef struct scsi_page_list {
LBITFIELD8_2(
device_type : 5,
device_qualifier : 3
);
uint8 page_code;
uint8 _res2;
uint8 page_length;
uint8 pages[1]; // size according to page_length
} _PACKED scsi_page_list;
// vital product data: unit serial number page
#define SCSI_PAGE_USN 0x80
typedef struct scsi_page_usn {
LBITFIELD8_2(
device_type : 5,
@ -325,6 +343,57 @@ typedef struct scsi_page_usn {
char psn[1]; // size according to page_length
} _PACKED scsi_page_usn;
typedef struct scsi_page_block_limits {
LBITFIELD8_2(
device_type : 5,
device_qualifier : 3
);
uint8 page_code;
uint16 _page_length;
LBITFIELD8_2(
wsnz : 1,
_res4_1 : 7
);
uint8 max_cmp_write_length;
uint16 opt_transfer_length_grain;
uint32 max_transfer_length;
uint32 opt_transfer_length;
uint32 max_prefetch_length;
uint32 max_unmap_lba_count;
uint32 max_unmap_blk_count;
uint32 opt_unmap_grain;
uint32 unmap_grain_align;
uint64 max_write_same_length;
uint8 _res44[20];
} _PACKED scsi_page_block_limits;
typedef struct scsi_page_lb_provisioning {
LBITFIELD8_2(
device_type : 5,
device_qualifier : 3
);
uint8 page_code;
uint16 page_length;
uint8 threshold_exponent;
LBITFIELD8_7(
dp : 1,
anc_sup : 1,
lbprz : 1,
_res5_3 : 2,
lbpws10 : 1,
lbpws : 1,
lbpu : 1
);
LBITFIELD8_2(
provisioning_type : 3,
_res6_3 : 5
);
uint8 _res7;
} _PACKED scsi_page_lb_provisioning;
// READ CAPACITY (10)
typedef struct scsi_cmd_read_capacity {

View File

@ -31,6 +31,70 @@ inquiry(scsi_periph_device_info *device, scsi_inquiry *inquiry)
}
static status_t
vpd_page_inquiry(scsi_periph_device_info *device, uint8 page, void* data,
uint16 length)
{
SHOW_FLOW0(0, "");
scsi_ccb* ccb = device->scsi->alloc_ccb(device->scsi_device);
if (ccb == NULL)
return B_NO_MEMORY;
scsi_cmd_inquiry *cmd = (scsi_cmd_inquiry *)ccb->cdb;
memset(cmd, 0, sizeof(scsi_cmd_inquiry));
cmd->opcode = SCSI_OP_INQUIRY;
cmd->lun = ccb->target_lun;
cmd->evpd = 1;
cmd->page_code = page;
cmd->allocation_length = length;
ccb->flags = SCSI_DIR_IN;
ccb->cdb_length = sizeof(scsi_cmd_inquiry);
ccb->sort = -1;
ccb->timeout = device->std_timeout;
ccb->data = (uint8*)data;
ccb->sg_list = NULL;
ccb->data_length = length;
status_t status = periph_safe_exec(device, ccb);
device->scsi->free_ccb(ccb);
return status;
}
static status_t
vpd_page_get(scsi_periph_device_info *device, uint8 page, void* data,
uint16 length)
{
SHOW_FLOW0(0, "");
status_t status = vpd_page_inquiry(device, 0, data, length);
if (status != B_OK)
return status; // or B_BAD_VALUE
if (page == 0)
return B_OK;
scsi_page_list *list_data = (scsi_page_list*)data;
int page_length = min_c(list_data->page_length, length -
offsetof(scsi_page_list, pages));
for (int i = 0; i < page_length; i++) {
if (list_data->pages[i] == page)
return vpd_page_inquiry(device, page, data, length);
}
// TODO buffer might be not big enough
return B_BAD_VALUE;
}
static status_t
prevent_allow(scsi_periph_device_info *device, bool prevent)
{