minix/drivers/usb_storage/scsi.c
Wojciech Zajac 78cd341562 Fixed usb_storage to support more USB sticks
More TEST UNIT READY calls, as some sticks seem to require them, while others are indifferent.

Mass storage 'reset recovery' is disabled by default, as it broke communication with some sticks.

Minor fixes.
2014-07-28 17:05:55 +02:00

267 lines
7.8 KiB
C
Executable file

/*
* 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;
}