minix/drivers/usb_storage/scsi.c

267 lines
7.8 KiB
C
Raw Normal View History

/*
* SCSI commands related implementation
*/
#include <minix/blockdriver.h> /* SECTOR_SIZE */
#include <assert.h>
#include <string.h> /* strncpy */
#include "common.h"
#include "scsi.h"
/*---------------------------*
* declared functions *
*---------------------------*/
/* To work correctly cbw->CBWCB must be zeroed before calling these: */
static int create_inquiry_scsi_cmd(mass_storage_cbw *);
static int create_test_scsi_cmd(mass_storage_cbw *);
static int create_read_capacity_scsi_cmd(mass_storage_cbw *);
static int create_write_scsi_cmd(mass_storage_cbw *, scsi_transfer *);
static int create_read_scsi_cmd(mass_storage_cbw *, scsi_transfer *);
static int create_mode_sense_scsi_cmd(mass_storage_cbw *);
/*---------------------------*
* defined functions *
*---------------------------*/
/*===========================================================================*
* create_scsi_cmd *
*===========================================================================*/
int
create_scsi_cmd(mass_storage_cbw * cbw, int cmd, scsi_transfer * info)
{
MASS_DEBUG_DUMP;
assert(NULL != cbw);
switch (cmd) {
case SCSI_INQUIRY:
return create_inquiry_scsi_cmd(cbw);
case SCSI_TEST_UNIT_READY:
return create_test_scsi_cmd(cbw);
case SCSI_READ_CAPACITY:
return create_read_capacity_scsi_cmd(cbw);
case SCSI_WRITE:
return create_write_scsi_cmd(cbw, info);
case SCSI_READ:
return create_read_scsi_cmd(cbw, info);
case SCSI_MODE_SENSE:
return create_mode_sense_scsi_cmd(cbw);
default:
MASS_MSG("Invalid SCSI command!");
return EXIT_FAILURE;
}
}
/*===========================================================================*
* create_inquiry_scsi_cmd *
*===========================================================================*/
static int
create_inquiry_scsi_cmd(mass_storage_cbw * cbw)
{
MASS_DEBUG_DUMP;
cbw->dCBWDataTransferLength = SCSI_INQUIRY_DATA_LEN;
cbw->bCBWFlags = CBW_FLAGS_IN;
cbw->bCDBLength = SCSI_INQUIRY_CMD_LEN;
SCSI_SET_INQUIRY_OP_CODE(cbw->CBWCB);
SCSI_SET_INQUIRY_PAGE_CODE(cbw->CBWCB, 0);
SCSI_SET_INQUIRY_ALLOC_LEN(cbw->CBWCB, SCSI_INQUIRY_DATA_LEN);
return EXIT_SUCCESS;
}
/*===========================================================================*
* create_test_scsi_cmd *
*===========================================================================*/
static int
create_test_scsi_cmd(mass_storage_cbw * cbw)
{
MASS_DEBUG_DUMP;
cbw->bCDBLength = SCSI_TEST_CMD_LEN;
SCSI_SET_TEST_OP_CODE(cbw->CBWCB);
return EXIT_SUCCESS;
}
/*===========================================================================*
* create_read_capacity_scsi_cmd *
*===========================================================================*/
static int
create_read_capacity_scsi_cmd(mass_storage_cbw * cbw)
{
MASS_DEBUG_DUMP;
cbw->dCBWDataTransferLength = SCSI_READ_CAPACITY_DATA_LEN;
cbw->bCBWFlags = CBW_FLAGS_IN;
cbw->bCDBLength = SCSI_READ_CAPACITY_CMD_LEN;
SCSI_SET_READ_CAPACITY_OP_CODE(cbw->CBWCB);
SCSI_SET_READ_CAPACITY_LBA(cbw->CBWCB, 0x00);
return EXIT_SUCCESS;
}
/*===========================================================================*
* create_write_scsi_cmd *
*===========================================================================*/
static int
create_write_scsi_cmd(mass_storage_cbw * cbw, scsi_transfer * info)
{
MASS_DEBUG_DUMP;
assert(NULL != info);
assert(0 == (info->length % SECTOR_SIZE));
cbw->dCBWDataTransferLength = info->length;
cbw->bCBWFlags = CBW_FLAGS_OUT;
cbw->bCDBLength = SCSI_WRITE_CMD_LEN;
SCSI_SET_WRITE_OP_CODE(cbw->CBWCB);
SCSI_SET_WRITE_LBA(cbw->CBWCB, info->lba);
SCSI_SET_WRITE_BLEN(cbw->CBWCB, info->length / SECTOR_SIZE);
return EXIT_SUCCESS;
}
/*===========================================================================*
* create_read_scsi_cmd *
*===========================================================================*/
static int
create_read_scsi_cmd(mass_storage_cbw * cbw, scsi_transfer * info)
{
MASS_DEBUG_DUMP;
assert(NULL != info);
assert(0 == (info->length % SECTOR_SIZE));
cbw->dCBWDataTransferLength = info->length;
cbw->bCBWFlags = CBW_FLAGS_IN;
cbw->bCDBLength = SCSI_READ_CMD_LEN;
SCSI_SET_READ_OP_CODE(cbw->CBWCB);
SCSI_SET_READ_LBA(cbw->CBWCB, info->lba);
SCSI_SET_READ_BLEN(cbw->CBWCB, info->length / SECTOR_SIZE);
return EXIT_SUCCESS;
}
/*===========================================================================*
* create_mode_sense_scsi_cmd *
*===========================================================================*/
static int
create_mode_sense_scsi_cmd(mass_storage_cbw * cbw)
{
MASS_DEBUG_DUMP;
cbw->dCBWDataTransferLength = SCSI_MODE_SENSE_FLEX_DATA_LEN;
cbw->bCBWFlags = CBW_FLAGS_IN;
cbw->bCDBLength = SCSI_MODE_SENSE_CMD_LEN;
SCSI_SET_MODE_SENSE_OP_CODE(cbw->CBWCB);
SCSI_SET_MODE_SENSE_PAGE_CODE(cbw->CBWCB,
SCSI_MODE_SENSE_FLEXIBLE_DISK_PAGE);
return EXIT_SUCCESS;
}
/*===========================================================================*
* check_inquiry_reply *
*===========================================================================*/
int
check_inquiry_reply(uint8_t * scsi_reply)
{
char vendor_name[SCSI_INQUIRY_VENDOR_NAME_LEN + 1];
char product_name[SCSI_INQUIRY_PRODUCT_NAME_LEN + 1];
MASS_DEBUG_DUMP;
/* Stop condition for printing as strncpy() does not add it */
vendor_name[SCSI_INQUIRY_VENDOR_NAME_LEN] = '\0';
product_name[SCSI_INQUIRY_PRODUCT_NAME_LEN] = '\0';
if (SCSI_GET_INQUIRY_PERIPH_QUALIF(scsi_reply)) {
MASS_MSG("Device not connected");
return EXIT_FAILURE;
}
strncpy(vendor_name, SCSI_GET_INQUIRY_VENDOR_NAME(scsi_reply),
SCSI_INQUIRY_VENDOR_NAME_LEN);
strncpy(product_name, SCSI_GET_INQUIRY_PRODUCT_NAME(scsi_reply),
SCSI_INQUIRY_PRODUCT_NAME_LEN);
MASS_DEBUG_MSG("Vendor name: %s", vendor_name);
MASS_DEBUG_MSG("Product name %s", product_name);
return EXIT_SUCCESS;
}
/*===========================================================================*
* check_read_capacity_reply *
*===========================================================================*/
int
check_read_capacity_reply(uint8_t * scsi_reply, uint32_t * lba, uint32_t * blen)
{
MASS_DEBUG_DUMP;
*lba = SCSI_GET_READ_CAPACITY_LBA(scsi_reply);
*blen = SCSI_GET_READ_CAPACITY_BLEN(scsi_reply);
return EXIT_SUCCESS;
}
/*===========================================================================*
* check_mode_sense_reply *
*===========================================================================*/
int
check_mode_sense_reply(uint8_t * scsi_reply, unsigned * cyl,
unsigned * head, unsigned * sect)
{
MASS_DEBUG_DUMP;
*cyl = SCSI_GET_MODE_SENSE_CYLINDERS(scsi_reply);
*head = SCSI_GET_MODE_SENSE_HEADS(scsi_reply);
*sect = SCSI_GET_MODE_SENSE_SECTORS(scsi_reply);
return EXIT_SUCCESS;
}
/*===========================================================================*
* check_csw *
*===========================================================================*/
int
check_csw(mass_storage_csw * csw, unsigned int tag)
{
MASS_DEBUG_DUMP;
if (csw->dCSWTag != tag) {
MASS_MSG("CSW tag mismatch!");
return EXIT_FAILURE;
}
if (CSW_SIGNATURE != csw->dCSWSignature) {
MASS_MSG("CSW signature mismatch!");
return EXIT_FAILURE;
}
if (CSW_STATUS_GOOD != csw->bCSWStatus) {
MASS_MSG("CSW status error (0x%02X)!", csw->bCSWStatus);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}