/*
* Copyright (c) 2011 Jiri Svoboda
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/** @addtogroup libscsi
* @{
*/
/**
* @file SCSI Primary Commands.
*/
#ifndef LIBSCSI_SPC_H_
#define LIBSCSI_SPC_H_
#include <stdint.h>
#include <str.h>
/** SCSI command codes defined in SCSI-SPC */
enum scsi_cmd_spc {
SCSI_CMD_TEST_UNIT_READY = 0x00,
SCSI_CMD_REQUEST_SENSE = 0x03,
SCSI_CMD_INQUIRY = 0x12,
};
/** SCSI Inquiry command
*
* Note: for SFF 8020 the command must be zero-padded to 12 bytes
* and alloc_len must be <= 0xff.
*/
typedef struct {
/** Operation code (SCSI_CMD_INQUIRY) */
uint8_t op_code;
/** Reserved:7-2, obsolete:1, evpd:0 */
uint8_t evpd;
/* Page Code */
uint8_t page_code;
/* Allocation Length */
uint16_t alloc_len;
/* Control */
uint8_t control;
} __attribute__((packed)) scsi_cdb_inquiry_t;
/** Minimum size of inquiry data required since SCSI-2 */
#define SCSI_STD_INQUIRY_DATA_MIN_SIZE 36
/** Standard inquiry data.
*
* Returned for Inquiry command with evpd bit cleared.
*/
typedef struct {
/** Peripheral qualifier, Peripheral device type */
uint8_t pqual_devtype;
/** RMB, reserved */
uint8_t rmb;
/** Version */
uint8_t version;
/** Obsolete, NormACA, HiSup, Response Data Format */
uint8_t aca_hisup_rdf;
/** Additional Length */
uint8_t additional_len;
/** SCCS, ACC, TPGS, 3PC, Reserved, Protect */
uint8_t cap1;
/** Obsolete, EncServ, VS, MuliP, Obsolete, Addr16 */
uint8_t cap2;
/** Obsolete, WBus16, Sync, Obsolete, CmdQue, VS */
uint8_t cap3;
/** Vendor string */
uint8_t vendor[8];
/** Product string */
uint8_t product[16];
/** Revision string */
uint8_t revision[4];
/* End of required data */
} __attribute__((packed)) scsi_std_inquiry_data_t;
/** Size of struct or union member. */
#define SCSI_MEMBER_SIZE(type, member) \
(sizeof(((type *)0) -> member))
/** Size of string buffer needed to hold converted inquiry vendor string */
#define SCSI_INQ_VENDOR_STR_BUFSIZE \
SPASCII_STR_BUFSIZE(SCSI_MEMBER_SIZE(scsi_std_inquiry_data_t, vendor))
/** Size of string buffer needed to hold converted inquiry product string */
#define SCSI_INQ_PRODUCT_STR_BUFSIZE \
SPASCII_STR_BUFSIZE(SCSI_MEMBER_SIZE(scsi_std_inquiry_data_t, product))
/** Size of string buffer needed to hold converted inquiry revision string */
#define SCSI_INQ_REVISION_STR_BUFSIZE \
SPASCII_STR_BUFSIZE(SCSI_MEMBER_SIZE(scsi_std_inquiry_data_t, revision))
/** Bits in scsi_std_inquiry_data_t.pqual_devtype */
enum scsi_pqual_devtype_bits {
/* Peripheral qualifier */
SCSI_PQDT_PQUAL_h = 7,
SCSI_PQDT_PQUAL_l = 5,
/* Peripheral device type */
SCSI_PQDT_DEV_TYPE_h = 4,
SCSI_PQDT_DEV_TYPE_l = 0
};
/** Bits in scsi_std_inquiry_data_t.rmb */
enum scsi_rmb_bits {
SCSI_RMB_RMB = 7
};
/** SCSI peripheral device type */
enum scsi_device_type {
SCSI_DEV_BLOCK = 0x00,
SCSI_DEV_STREAM = 0x01,
SCSI_DEV_CD_DVD = 0x05,
SCSI_DEV_CHANGER = 0x08,
SCSI_DEV_ENCLOSURE = 0x0d,
SCSI_DEV_OSD = 0x11,
SCSI_DEV_LIMIT = 0x20
};
/** SCSI Request Sense command */
typedef struct {
/** Operation code (SCSI_CMD_REQUEST_SENSE) */
uint8_t op_code;
/** Reserved, Desc */
uint8_t desc;
/* Reserved */
uint16_t res_2;
/* Allocation Length */
uint8_t alloc_len;
/* Control */
uint8_t control;
} __attribute__((packed)) scsi_cdb_request_sense_t;
/** Minimum size of sense data.
*
* If the target returns less data, the missing bytes should be considered
* zero.
*/
#define SCSI_SENSE_DATA_MIN_SIZE 18
/** Maximum size of sense data */
#define SCSI_SENSE_DATA_MAX_SIZE 252
/** Fixed-format sense data.
*
* Returned for Request Sense command with Desc bit cleared.
*/
typedef struct {
/** Valid, Response Code */
uint8_t valid_rcode;
/** Peripheral qualifier, Peripheral device type */
uint8_t obsolete_1;
/** Filemark, EOM, ILI, Reserved, Sense Key */
uint8_t flags_key;
/** Information */
uint32_t info;
/** Additional Sense Length */
uint8_t additional_len;
/** Command-specific Information */
uint32_t cmd_spec;
/** Additional Sense Code */
uint8_t additional_code;
/** Additional Sense Code Qualifier */
uint8_t additional_cqual;
/** Field-replaceable Unit Code */
uint8_t fru_code;
/** SKSV, Sense-key specific */
uint8_t key_spec[3];
} __attribute__((packed)) scsi_sense_data_t;
/** Sense key */
enum scsi_sense_key {
SCSI_SK_NO_SENSE = 0x0,
SCSI_SK_RECOVERED_ERROR = 0x1,
SCSI_SK_NOT_READY = 0x2,
SCSI_SK_MEDIUM_ERROR = 0x3,
SCSI_SK_HARDWARE_ERROR = 0x4,
SCSI_SK_ILLEGAL_REQUEST = 0x5,
SCSI_SK_UNIT_ATTENTION = 0x6,
SCSI_SK_DATA_PROTECT = 0x7,
SCSI_SK_BLANK_CHECK = 0x8,
SCSI_SK_VENDOR_SPECIFIC = 0x9,
SCSI_SK_COPY_ABORTED = 0xa,
SCSI_SK_ABORTED_COMMAND = 0xb,
SCSI_SK_VOLUME_OVERFLOW = 0xd,
SCSI_SK_MISCOMPARE = 0xe,
SCSI_SK_LIMIT = 0x10
};
extern const char *scsi_dev_type_str[SCSI_DEV_LIMIT];
extern const char *scsi_sense_key_str[SCSI_SK_LIMIT];
extern const char *scsi_get_dev_type_str(unsigned);
extern const char *scsi_get_sense_key_str(unsigned);
/** SCSI Test Unit Ready command */
typedef struct {
/** Operation code (SCSI_CMD_TEST_UNIT_READY) */
uint8_t op_code;
/** Reserved */
uint32_t reserved;
/* Control */
uint8_t control;
} __attribute__((packed)) scsi_cdb_test_unit_ready_t;
#endif
/** @}
*/