78cd341562
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.
266 lines
7.8 KiB
C
Executable file
266 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;
|
|
}
|