mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-14 14:55:41 +00:00
SCSI Peripheral drivers for CAM:
da - Direct Access Devices (disks, optical devices, SS disks) cd - CDROM (or devices that can act like them, WORM, CD-RW, etc) ch - Medium Changer devices. sa - Sequential Access Devices (tape drives) pass - Application pass-thru driver targ - Target Mode "Processor Target" Emulator pt - Processor Target Devices (scanners, cpus, etc.) Submitted by: The CAM Team
This commit is contained in:
parent
8b8a9b1d3e
commit
76babe507b
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=39213
2678
sys/cam/scsi/scsi_all.c
Normal file
2678
sys/cam/scsi/scsi_all.c
Normal file
File diff suppressed because it is too large
Load Diff
814
sys/cam/scsi/scsi_all.h
Normal file
814
sys/cam/scsi/scsi_all.h
Normal file
@ -0,0 +1,814 @@
|
||||
/*
|
||||
* Largely written by Julian Elischer (julian@tfs.com)
|
||||
* for TRW Financial Systems.
|
||||
*
|
||||
* TRW Financial Systems, in accordance with their agreement with Carnegie
|
||||
* Mellon University, makes this software available to CMU to distribute
|
||||
* or use in any manner that they see fit as long as this message is kept with
|
||||
* the software. For this reason TFS also grants any other persons or
|
||||
* organisations permission to use or modify this software.
|
||||
*
|
||||
* TFS supplies this software to be publicly redistributed
|
||||
* on the understanding that TFS is not responsible for the correct
|
||||
* functioning of this software in any circumstances.
|
||||
*
|
||||
* Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
|
||||
*
|
||||
* $Id: scsi_all.h,v 1.13 1995/05/30 08:13:25 rgrimes Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* SCSI general interface description
|
||||
*/
|
||||
|
||||
#ifndef _SCSI_SCSI_ALL_H
|
||||
#define _SCSI_SCSI_ALL_H 1
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
/*
|
||||
* SCSI command format
|
||||
*/
|
||||
|
||||
/*
|
||||
* Define dome bits that are in ALL (or a lot of) scsi commands
|
||||
*/
|
||||
#define SCSI_CTL_LINK 0x01
|
||||
#define SCSI_CTL_FLAG 0x02
|
||||
#define SCSI_CTL_VENDOR 0xC0
|
||||
#define SCSI_CMD_LUN 0xA0 /* these two should not be needed */
|
||||
#define SCSI_CMD_LUN_SHIFT 5 /* LUN in the cmd is no longer SCSI */
|
||||
|
||||
#define SCSI_MAX_CDBLEN 16 /*
|
||||
* 16 byte commands are in the
|
||||
* SCSI-3 spec
|
||||
*/
|
||||
#if defined(CAM_MAX_CDBLEN) && (CAM_MAX_CDBLEN < SCSI_MAX_CDBLEN)
|
||||
#error "CAM_MAX_CDBLEN cannot be less than SCSI_MAX_CDBLEN"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This type defines actions to be taken when a particular sense code is
|
||||
* received. Right now, these flags are only defined to take up 16 bits,
|
||||
* but can be expanded in the future if necessary.
|
||||
*/
|
||||
typedef enum {
|
||||
SS_NOP = 0x000000, /* Do nothing */
|
||||
SS_RETRY = 0x010000, /* Retry the command */
|
||||
SS_FAIL = 0x020000, /* Bail out */
|
||||
SS_START = 0x030000, /* Send a Start Unit command to the device,
|
||||
* then retry the original command.
|
||||
*/
|
||||
SS_TUR = 0x040000, /* Send a Test Unit Ready command to the
|
||||
* device, then retry the original command.
|
||||
*/
|
||||
SS_MANUAL = 0x050000, /*
|
||||
* This error must be handled manually,
|
||||
* i.e. the code must look at the asc and
|
||||
* ascq values and determine the proper
|
||||
* course of action.
|
||||
*/
|
||||
SS_TURSTART = 0x060000, /*
|
||||
* Send a Test Unit Ready command to the
|
||||
* device, and if that fails, send a start
|
||||
* unit.
|
||||
*/
|
||||
SS_MASK = 0xff0000
|
||||
} scsi_sense_action;
|
||||
|
||||
typedef enum {
|
||||
SSQ_NONE = 0x0000,
|
||||
SSQ_DECREMENT_COUNT = 0x0100, /* Decrement the retry count */
|
||||
SSQ_MANY = 0x0200, /* send lots of recovery commands */
|
||||
SSQ_RANGE = 0x0400, /*
|
||||
* Yes, this is a hack. Basically,
|
||||
* if this flag is set then it
|
||||
* represents an ascq range. The
|
||||
* "correct" way to implement the
|
||||
* ranges might be to add a special
|
||||
* field to the sense code table,
|
||||
* but that would take up a lot of
|
||||
* additional space. This solution
|
||||
* isn't as elegant, but is more
|
||||
* space efficient.
|
||||
*/
|
||||
SSQ_PRINT_SENSE = 0x0800,
|
||||
SSQ_MASK = 0xff00
|
||||
} scsi_sense_action_qualifier;
|
||||
|
||||
/* Mask for error status values */
|
||||
#define SS_ERRMASK 0xff
|
||||
|
||||
/* The default error action */
|
||||
#define SS_DEF SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE|EIO
|
||||
|
||||
/* Default error action, without an error return value */
|
||||
#define SS_NEDEF SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE
|
||||
|
||||
/* Default error action, without sense printing or an error return value */
|
||||
#define SS_NEPDEF SS_RETRY|SSQ_DECREMENT_COUNT
|
||||
|
||||
struct scsi_generic
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t bytes[11];
|
||||
};
|
||||
|
||||
struct scsi_request_sense
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t byte2;
|
||||
u_int8_t unused[2];
|
||||
u_int8_t length;
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
struct scsi_test_unit_ready
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t byte2;
|
||||
u_int8_t unused[3];
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
struct scsi_send_diag
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t byte2;
|
||||
#define SSD_UOL 0x01
|
||||
#define SSD_DOL 0x02
|
||||
#define SSD_SELFTEST 0x04
|
||||
#define SSD_PF 0x10
|
||||
u_int8_t unused[1];
|
||||
u_int8_t paramlen[2];
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
struct scsi_sense
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t byte2;
|
||||
u_int8_t unused[2];
|
||||
u_int8_t length;
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
struct scsi_inquiry
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t byte2;
|
||||
#define SI_EVPD 0x01
|
||||
u_int8_t page_code;
|
||||
u_int8_t reserved;
|
||||
u_int8_t length;
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
struct scsi_mode_sense_6
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t byte2;
|
||||
#define SMS_DBD 0x08
|
||||
u_int8_t page;
|
||||
#define SMS_PAGE_CODE 0x3F
|
||||
#define SMS_VENDOR_SPECIFIC_PAGE 0x00
|
||||
#define SMS_DISCONNECT_RECONNECT_PAGE 0x02
|
||||
#define SMS_PERIPHERAL_DEVICE_PAGE 0x09
|
||||
#define SMS_CONTROL_MODE_PAGE 0x0A
|
||||
#define SMS_ALL_PAGES_PAGE 0x3F
|
||||
#define SMS_PAGE_CTRL_MASK 0xC0
|
||||
#define SMS_PAGE_CTRL_CURRENT 0x00
|
||||
#define SMS_PAGE_CTRL_CHANGEABLE 0x40
|
||||
#define SMS_PAGE_CTRL_DEFAULT 0x80
|
||||
#define SMS_PAGE_CTRL_SAVED 0xC0
|
||||
u_int8_t unused;
|
||||
u_int8_t length;
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
struct scsi_mode_sense_10
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t byte2; /* same bits as small version */
|
||||
u_int8_t page; /* same bits as small version */
|
||||
u_int8_t unused[4];
|
||||
u_int8_t length[2];
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
struct scsi_mode_select_6
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t byte2;
|
||||
#define SMS_SP 0x01
|
||||
#define SMS_PF 0x10
|
||||
u_int8_t unused[2];
|
||||
u_int8_t length;
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
struct scsi_mode_select_10
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t byte2; /* same bits as small version */
|
||||
u_int8_t unused[5];
|
||||
u_int8_t length[2];
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
/*
|
||||
* When sending a mode select to a tape drive, the medium type must be 0.
|
||||
*/
|
||||
struct scsi_mode_hdr_6
|
||||
{
|
||||
u_int8_t datalen;
|
||||
u_int8_t medium_type;
|
||||
u_int8_t dev_specific;
|
||||
u_int8_t block_descr_len;
|
||||
};
|
||||
|
||||
struct scsi_mode_hdr_10
|
||||
{
|
||||
u_int8_t datalen[2];
|
||||
u_int8_t medium_type;
|
||||
u_int8_t dev_specific;
|
||||
u_int8_t reserved[2];
|
||||
u_int8_t block_descr_len[2];
|
||||
};
|
||||
|
||||
struct scsi_mode_block_descr
|
||||
{
|
||||
u_int8_t density_code;
|
||||
u_int8_t num_blocks[3];
|
||||
u_int8_t reserved;
|
||||
u_int8_t block_len[3];
|
||||
};
|
||||
|
||||
struct scsi_control_page {
|
||||
u_int8_t page_code;
|
||||
u_int8_t page_length;
|
||||
u_int8_t rlec;
|
||||
#define SCB_RLEC 0x01 /*Report Log Exception Cond*/
|
||||
u_int8_t queue_flags;
|
||||
#define SCP_QUEUE_ALG_MASK 0xF0
|
||||
#define SCP_QUEUE_ALG_RESTRICTED 0x00
|
||||
#define SCP_QUEUE_ALG_UNRESTRICTED 0x10
|
||||
#define SCP_QUEUE_ERR 0x02 /*Queued I/O aborted for CACs*/
|
||||
#define SCP_QUEUE_DQUE 0x01 /*Queued I/O disabled*/
|
||||
u_int8_t eca_and_aen;
|
||||
#define SCP_EECA 0x80 /*Enable Extended CA*/
|
||||
#define SCP_RAENP 0x04 /*Ready AEN Permission*/
|
||||
#define SCP_UAAENP 0x02 /*UA AEN Permission*/
|
||||
#define SCP_EAENP 0x01 /*Error AEN Permission*/
|
||||
u_int8_t reserved;
|
||||
u_int8_t aen_holdoff_period[2];
|
||||
};
|
||||
|
||||
struct scsi_reserve
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t byte2;
|
||||
u_int8_t unused[2];
|
||||
u_int8_t length;
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
struct scsi_release
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t byte2;
|
||||
u_int8_t unused[2];
|
||||
u_int8_t length;
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
struct scsi_prevent
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t byte2;
|
||||
u_int8_t unused[2];
|
||||
u_int8_t how;
|
||||
u_int8_t control;
|
||||
};
|
||||
#define PR_PREVENT 0x01
|
||||
#define PR_ALLOW 0x00
|
||||
|
||||
struct scsi_sync_cache
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t byte2;
|
||||
u_int8_t begin_lba[4];
|
||||
u_int8_t reserved;
|
||||
u_int8_t lb_count[2];
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
|
||||
struct scsi_changedef
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t byte2;
|
||||
u_int8_t unused1;
|
||||
u_int8_t how;
|
||||
u_int8_t unused[4];
|
||||
u_int8_t datalen;
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
struct scsi_read_buffer
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t byte2;
|
||||
#define RWB_MODE 0x07
|
||||
#define RWB_MODE_HDR_DATA 0x00
|
||||
#define RWB_MODE_DATA 0x02
|
||||
#define RWB_MODE_DOWNLOAD 0x04
|
||||
#define RWB_MODE_DOWNLOAD_SAVE 0x05
|
||||
u_int8_t buffer_id;
|
||||
u_int8_t offset[3];
|
||||
u_int8_t length[3];
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
struct scsi_write_buffer
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t byte2;
|
||||
u_int8_t buffer_id;
|
||||
u_int8_t offset[3];
|
||||
u_int8_t length[3];
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
#define SC_SCSI_1 0x01
|
||||
#define SC_SCSI_2 0x03
|
||||
|
||||
/*
|
||||
* Opcodes
|
||||
*/
|
||||
|
||||
#define TEST_UNIT_READY 0x00
|
||||
#define REQUEST_SENSE 0x03
|
||||
#define INQUIRY 0x12
|
||||
#define MODE_SELECT_6 0x15
|
||||
#define MODE_SENSE_6 0x1a
|
||||
#define START_STOP 0x1b
|
||||
#define RESERVE 0x16
|
||||
#define RELEASE 0x17
|
||||
#define PREVENT_ALLOW 0x1e
|
||||
#define READ_CAPACITY 0x25
|
||||
#define POSITION_TO_ELEMENT 0x2b
|
||||
#define SYNCHRONIZE_CACHE 0x35
|
||||
#define WRITE_BUFFER 0x3b
|
||||
#define READ_BUFFER 0x3c
|
||||
#define CHANGE_DEFINITION 0x40
|
||||
#define MODE_SELECT_10 0x55
|
||||
#define MODE_SENSE_10 0x5A
|
||||
#define MOVE_MEDIUM 0xa5
|
||||
#define READ_ELEMENT_STATUS 0xb8
|
||||
|
||||
|
||||
/*
|
||||
* Device Types
|
||||
*/
|
||||
#define T_DIRECT 0x00
|
||||
#define T_SEQUENTIAL 0x01
|
||||
#define T_PRINTER 0x02
|
||||
#define T_PROCESSOR 0x03
|
||||
#define T_WORM 0x04
|
||||
#define T_CDROM 0x05
|
||||
#define T_SCANNER 0x06
|
||||
#define T_OPTICAL 0x07
|
||||
#define T_CHANGER 0x08
|
||||
#define T_COMM 0x09
|
||||
#define T_ASC0 0x0a
|
||||
#define T_ASC1 0x0b
|
||||
#define T_STORARRAY 0x0c
|
||||
#define T_ENCLOSURE 0x0d
|
||||
#define T_NODEVICE 0x1F
|
||||
#define T_ANY 0xFF /* Used in Quirk table matches */
|
||||
|
||||
#define T_REMOV 1
|
||||
#define T_FIXED 0
|
||||
|
||||
struct scsi_inquiry_data
|
||||
{
|
||||
u_int8_t device;
|
||||
#define SID_TYPE(inq_data) ((inq_data)->device & 0x1f)
|
||||
#define SID_QUAL(inq_data) (((inq_data)->device & 0xE0) >> 5)
|
||||
#define SID_QUAL_LU_CONNECTED 0x00 /* The specified peripheral device
|
||||
* type is currently connected to
|
||||
* logical unit. If the target cannot
|
||||
* determine whether or not a physical
|
||||
* device is currently connected, it
|
||||
* shall also use this peripheral
|
||||
* qualifier when returning the INQUIRY
|
||||
* data. This peripheral qualifier
|
||||
* does not mean that the device is
|
||||
* ready for access by the initiator.
|
||||
*/
|
||||
#define SID_QUAL_LU_OFFLINE 0x01 /* The target is capable of supporting
|
||||
* the specified peripheral device type
|
||||
* on this logical unit; however, the
|
||||
* physical device is not currently
|
||||
* connected to this logical unit.
|
||||
*/
|
||||
#define SID_QUAL_RSVD 0x02
|
||||
#define SID_QUAL_BAD_LU 0x03 /* The target is not capable of
|
||||
* supporting a physical device on
|
||||
* this logical unit. For this
|
||||
* peripheral qualifier the peripheral
|
||||
* device type shall be set to 1Fh to
|
||||
* provide compatibility with previous
|
||||
* versions of SCSI. All other
|
||||
* peripheral device type values are
|
||||
* reserved for this peripheral
|
||||
* qualifier.
|
||||
*/
|
||||
#define SID_QUAL_IS_VENDOR_UNIQUE(inq_data) ((SID_QUAL(inq_data) & 0x08) != 0)
|
||||
u_int8_t dev_qual2;
|
||||
#define SID_QUAL2 0x7F
|
||||
#define SID_IS_REMOVABLE(inq_data) (((inq_data)->dev_qual2 & 0x80) != 0)
|
||||
u_int8_t version;
|
||||
#define SID_ANSI_REV(inq_data) ((inq_data)->version & 0x07)
|
||||
#define SID_ECMA 0x38
|
||||
#define SID_ISO 0xC0
|
||||
u_int8_t response_format;
|
||||
#define SID_AENC 0x80
|
||||
#define SID_TrmIOP 0x40
|
||||
u_int8_t additional_length;
|
||||
u_int8_t reserved[2];
|
||||
u_int8_t flags;
|
||||
#define SID_SftRe 0x01
|
||||
#define SID_CmdQue 0x02
|
||||
#define SID_Linked 0x08
|
||||
#define SID_Sync 0x10
|
||||
#define SID_WBus16 0x20
|
||||
#define SID_WBus32 0x40
|
||||
#define SID_RelAdr 0x80
|
||||
#define SID_VENDOR_SIZE 8
|
||||
char vendor[SID_VENDOR_SIZE];
|
||||
#define SID_PRODUCT_SIZE 16
|
||||
char product[SID_PRODUCT_SIZE];
|
||||
#define SID_REVISION_SIZE 4
|
||||
char revision[SID_REVISION_SIZE];
|
||||
};
|
||||
|
||||
struct scsi_vpd_unit_serial_number
|
||||
{
|
||||
u_int8_t device;
|
||||
u_int8_t page_code;
|
||||
#define SVPD_UNIT_SERIAL_NUMBER 0x80
|
||||
u_int8_t reserved;
|
||||
u_int8_t length; /* serial number length */
|
||||
#define SVPD_SERIAL_NUM_SIZE 251
|
||||
char serial_num[SVPD_SERIAL_NUM_SIZE];
|
||||
};
|
||||
|
||||
struct scsi_read_capacity
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t byte2;
|
||||
u_int8_t addr[4];
|
||||
u_int8_t unused[3];
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
struct scsi_read_capacity_data
|
||||
{
|
||||
u_int8_t addr[4];
|
||||
u_int8_t length[4];
|
||||
};
|
||||
|
||||
struct scsi_sense_data
|
||||
{
|
||||
u_int8_t error_code;
|
||||
#define SSD_ERRCODE 0x7F
|
||||
#define SSD_CURRENT_ERROR 0x70
|
||||
#define SSD_DEFERRED_ERROR 0x71
|
||||
#define SSD_ERRCODE_VALID 0x80
|
||||
u_int8_t segment;
|
||||
u_int8_t flags;
|
||||
#define SSD_KEY 0x0F
|
||||
#define SSD_KEY_NO_SENSE 0x00
|
||||
#define SSD_KEY_RECOVERED_ERROR 0x01
|
||||
#define SSD_KEY_NOT_READY 0x02
|
||||
#define SSD_KEY_MEDIUM_ERROR 0x03
|
||||
#define SSD_KEY_HARDWARE_ERROR 0x04
|
||||
#define SSD_KEY_ILLEGAL_REQUEST 0x05
|
||||
#define SSD_KEY_UNIT_ATTENTION 0x06
|
||||
#define SSD_KEY_DATA_PROTECT 0x07
|
||||
#define SSD_KEY_BLANK_CHECK 0x08
|
||||
#define SSD_KEY_Vendor_Specific 0x09
|
||||
#define SSD_KEY_COPY_ABORTED 0x0a
|
||||
#define SSD_KEY_ABORTED_COMMAND 0x0b
|
||||
#define SSD_KEY_EQUAL 0x0c
|
||||
#define SSD_KEY_VOLUME_OVERFLOW 0x0d
|
||||
#define SSD_KEY_MISCOMPARE 0x0e
|
||||
#define SSD_KEY_RESERVED 0x0f
|
||||
#define SSD_ILI 0x20
|
||||
#define SSD_EOM 0x40
|
||||
#define SSD_FILEMARK 0x80
|
||||
u_int8_t info[4];
|
||||
u_int8_t extra_len;
|
||||
u_int8_t cmd_spec_info[4];
|
||||
u_int8_t add_sense_code;
|
||||
u_int8_t add_sense_code_qual;
|
||||
u_int8_t fru;
|
||||
u_int8_t sense_key_spec[3];
|
||||
#define SSD_SCS_VALID 0x80
|
||||
#define SSD_FIELDPTR_CMD 0x40
|
||||
#define SSD_BITPTR_VALID 0x08
|
||||
#define SSD_BITPTR_VALUE 0x07
|
||||
#define SSD_MIN_SIZE 18
|
||||
u_int8_t extra_bytes[14];
|
||||
#define SSD_FULL_SIZE sizeof(struct scsi_sense_data)
|
||||
};
|
||||
|
||||
struct scsi_mode_header_6
|
||||
{
|
||||
u_int8_t data_length; /* Sense data length */
|
||||
u_int8_t medium_type;
|
||||
u_int8_t dev_spec;
|
||||
u_int8_t blk_desc_len;
|
||||
};
|
||||
|
||||
struct scsi_mode_header_10
|
||||
{
|
||||
u_int8_t data_length[2];/* Sense data length */
|
||||
u_int8_t medium_type;
|
||||
u_int8_t dev_spec;
|
||||
u_int8_t unused[2];
|
||||
u_int8_t blk_desc_len[2];
|
||||
};
|
||||
|
||||
struct scsi_mode_blk_desc
|
||||
{
|
||||
u_int8_t density;
|
||||
u_int8_t nblocks[3];
|
||||
u_int8_t reserved;
|
||||
u_int8_t blklen[3];
|
||||
};
|
||||
|
||||
/*
|
||||
* Status Byte
|
||||
*/
|
||||
#define SCSI_STATUS_OK 0x00
|
||||
#define SCSI_STATUS_CHECK_COND 0x02
|
||||
#define SCSI_STATUS_COND_MET 0x04
|
||||
#define SCSI_STATUS_BUSY 0x08
|
||||
#define SCSI_STATUS_INTERMED 0x10
|
||||
#define SCSI_STATUS_INTERMED_COND_MET 0x14
|
||||
#define SCSI_STATUS_RESERV_CONFLICT 0x18
|
||||
#define SCSI_STATUS_CMD_TERMINATED 0x22
|
||||
#define SCSI_STATUS_QUEUE_FULL 0x28
|
||||
|
||||
struct scsi_inquiry_pattern {
|
||||
u_int8_t type;
|
||||
u_int8_t media_type;
|
||||
#define SIP_MEDIA_REMOVABLE 0x01
|
||||
#define SIP_MEDIA_FIXED 0x02
|
||||
const char *vendor;
|
||||
const char *product;
|
||||
const char *revision;
|
||||
};
|
||||
|
||||
struct scsi_static_inquiry_pattern {
|
||||
u_int8_t type;
|
||||
u_int8_t media_type;
|
||||
char vendor[SID_VENDOR_SIZE+1];
|
||||
char product[SID_PRODUCT_SIZE+1];
|
||||
char revision[SID_REVISION_SIZE+1];
|
||||
};
|
||||
|
||||
struct scsi_sense_quirk_entry {
|
||||
struct scsi_inquiry_pattern inq_pat;
|
||||
int num_ascs;
|
||||
struct asc_table_entry *asc_info;
|
||||
};
|
||||
|
||||
struct asc_table_entry {
|
||||
u_int8_t asc;
|
||||
u_int8_t ascq;
|
||||
u_int32_t action;
|
||||
#if !defined(SCSI_NO_SENSE_STRINGS)
|
||||
const char *desc;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct op_table_entry {
|
||||
u_int8_t opcode;
|
||||
u_int16_t opmask;
|
||||
const char *desc;
|
||||
};
|
||||
|
||||
struct scsi_op_quirk_entry {
|
||||
struct scsi_inquiry_pattern inq_pat;
|
||||
int num_ops;
|
||||
struct op_table_entry *op_table;
|
||||
};
|
||||
|
||||
|
||||
struct ccb_scsiio;
|
||||
struct cam_periph;
|
||||
union ccb;
|
||||
#ifndef KERNEL
|
||||
struct cam_device;
|
||||
#endif
|
||||
|
||||
extern const char *scsi_sense_key_text[];
|
||||
|
||||
__BEGIN_DECLS
|
||||
const char * scsi_sense_desc(int asc, int ascq,
|
||||
struct scsi_inquiry_data *inq_data);
|
||||
scsi_sense_action scsi_error_action(int asc, int ascq,
|
||||
struct scsi_inquiry_data *inq_data);
|
||||
#ifdef KERNEL
|
||||
void scsi_sense_print(struct ccb_scsiio *csio);
|
||||
int scsi_interpret_sense(union ccb *ccb,
|
||||
u_int32_t sense_flags,
|
||||
u_int32_t *relsim_flags,
|
||||
u_int32_t *reduction,
|
||||
u_int32_t *timeout,
|
||||
scsi_sense_action error_action);
|
||||
#else
|
||||
char * scsi_sense_string(struct cam_device *device,
|
||||
struct ccb_scsiio *csio,
|
||||
char *str, int str_len);
|
||||
void scsi_sense_print(struct cam_device *device,
|
||||
struct ccb_scsiio *csio, FILE *ofile);
|
||||
int scsi_interpret_sense(struct cam_device *device,
|
||||
union ccb *ccb,
|
||||
u_int32_t sense_flags,
|
||||
u_int32_t *relsim_flags,
|
||||
u_int32_t *reduction,
|
||||
u_int32_t *timeout,
|
||||
scsi_sense_action error_action);
|
||||
#endif /* KERNEL */
|
||||
|
||||
#define SF_RETRY_UA 0x01
|
||||
#define SF_NO_PRINT 0x02
|
||||
#define SF_QUIET_IR 0x04 /* Be quiet about Illegal Request reponses */
|
||||
|
||||
|
||||
const char * scsi_op_desc(u_int16_t opcode,
|
||||
struct scsi_inquiry_data *inq_data);
|
||||
char * scsi_cdb_string(u_int8_t *cdb_ptr, char *cdb_string);
|
||||
|
||||
void scsi_print_inquiry(struct scsi_inquiry_data *inq_data);
|
||||
|
||||
u_int scsi_calc_syncsrate(u_int period_factor);
|
||||
u_int scsi_calc_syncparam(u_int period);
|
||||
|
||||
void scsi_test_unit_ready(struct ccb_scsiio *csio, u_int32_t retries,
|
||||
void (*cbfcnp)(struct cam_periph *,
|
||||
union ccb *),
|
||||
u_int8_t tag_action,
|
||||
u_int8_t sense_len, u_int32_t timeout);
|
||||
|
||||
void scsi_request_sense(struct ccb_scsiio *csio, u_int32_t retries,
|
||||
void (*cbfcnp)(struct cam_periph *,
|
||||
union ccb *),
|
||||
void *data_ptr, u_int8_t dxfer_len,
|
||||
u_int8_t tag_action, u_int8_t sense_len,
|
||||
u_int32_t timeout);
|
||||
|
||||
void scsi_inquiry(struct ccb_scsiio *csio, u_int32_t retries,
|
||||
void (*cbfcnp)(struct cam_periph *, union ccb *),
|
||||
u_int8_t tag_action, u_int8_t *inq_buf,
|
||||
u_int32_t inq_len, int evpd, u_int8_t page_code,
|
||||
u_int8_t sense_len, u_int32_t timeout);
|
||||
|
||||
void scsi_mode_sense(struct ccb_scsiio *csio, u_int32_t retries,
|
||||
void (*cbfcnp)(struct cam_periph *,
|
||||
union ccb *),
|
||||
u_int8_t tag_action, int dbd,
|
||||
u_int8_t page_code, u_int8_t page,
|
||||
u_int8_t *param_buf, u_int32_t param_len,
|
||||
u_int8_t sense_len, u_int32_t timeout);
|
||||
|
||||
void scsi_mode_select(struct ccb_scsiio *csio, u_int32_t retries,
|
||||
void (*cbfcnp)(struct cam_periph *,
|
||||
union ccb *),
|
||||
u_int8_t tag_action, int scsi_page_fmt,
|
||||
int save_pages, u_int8_t *param_buf,
|
||||
u_int32_t param_len, u_int8_t sense_len,
|
||||
u_int32_t timeout);
|
||||
|
||||
void scsi_read_capacity(struct ccb_scsiio *csio, u_int32_t retries,
|
||||
void (*cbfcnp)(struct cam_periph *,
|
||||
union ccb *), u_int8_t tag_action,
|
||||
struct scsi_read_capacity_data *rcap_buf,
|
||||
u_int8_t sense_len, u_int32_t timeout);
|
||||
|
||||
void scsi_prevent(struct ccb_scsiio *csio, u_int32_t retries,
|
||||
void (*cbfcnp)(struct cam_periph *, union ccb *),
|
||||
u_int8_t tag_action, u_int8_t action,
|
||||
u_int8_t sense_len, u_int32_t timeout);
|
||||
|
||||
void scsi_synchronize_cache(struct ccb_scsiio *csio,
|
||||
u_int32_t retries,
|
||||
void (*cbfcnp)(struct cam_periph *,
|
||||
union ccb *), u_int8_t tag_action,
|
||||
u_int32_t begin_lba, u_int16_t lb_count,
|
||||
u_int8_t sense_len, u_int32_t timeout);
|
||||
|
||||
int scsi_inquiry_match(caddr_t inqbuffer, caddr_t table_entry);
|
||||
int scsi_static_inquiry_match(caddr_t inqbuffer,
|
||||
caddr_t table_entry);
|
||||
|
||||
static __inline void scsi_extract_sense(struct scsi_sense_data *sense,
|
||||
int *error_code, int *sense_key,
|
||||
int *asc, int *ascq);
|
||||
static __inline void scsi_ulto2b(u_int32_t val, u_int8_t *bytes);
|
||||
static __inline void scsi_ulto3b(u_int32_t val, u_int8_t *bytes);
|
||||
static __inline void scsi_ulto4b(u_int32_t val, u_int8_t *bytes);
|
||||
static __inline u_int32_t scsi_2btoul(u_int8_t *bytes);
|
||||
static __inline u_int32_t scsi_3btoul(u_int8_t *bytes);
|
||||
static __inline int32_t scsi_3btol(u_int8_t *bytes);
|
||||
static __inline u_int32_t scsi_4btoul(u_int8_t *bytes);
|
||||
|
||||
|
||||
static __inline void scsi_extract_sense(struct scsi_sense_data *sense,
|
||||
int *error_code, int *sense_key,
|
||||
int *asc, int *ascq)
|
||||
{
|
||||
*error_code = sense->error_code & SSD_ERRCODE;
|
||||
*sense_key = sense->flags & SSD_KEY;
|
||||
*asc = (sense->extra_len >= 5) ? sense->add_sense_code : 0;
|
||||
*ascq = (sense->extra_len >= 6) ? sense->add_sense_code_qual : 0;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
scsi_ulto2b(u_int32_t val, u_int8_t *bytes)
|
||||
{
|
||||
|
||||
bytes[0] = (val >> 8) & 0xff;
|
||||
bytes[1] = val & 0xff;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
scsi_ulto3b(u_int32_t val, u_int8_t *bytes)
|
||||
{
|
||||
|
||||
bytes[0] = (val >> 16) & 0xff;
|
||||
bytes[1] = (val >> 8) & 0xff;
|
||||
bytes[2] = val & 0xff;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
scsi_ulto4b(u_int32_t val, u_int8_t *bytes)
|
||||
{
|
||||
|
||||
bytes[0] = (val >> 24) & 0xff;
|
||||
bytes[1] = (val >> 16) & 0xff;
|
||||
bytes[2] = (val >> 8) & 0xff;
|
||||
bytes[3] = val & 0xff;
|
||||
}
|
||||
|
||||
static __inline u_int32_t
|
||||
scsi_2btoul(u_int8_t *bytes)
|
||||
{
|
||||
u_int32_t rv;
|
||||
|
||||
rv = (bytes[0] << 8) |
|
||||
bytes[1];
|
||||
return (rv);
|
||||
}
|
||||
|
||||
static __inline u_int32_t
|
||||
scsi_3btoul(u_int8_t *bytes)
|
||||
{
|
||||
u_int32_t rv;
|
||||
|
||||
rv = (bytes[0] << 16) |
|
||||
(bytes[1] << 8) |
|
||||
bytes[2];
|
||||
return (rv);
|
||||
}
|
||||
|
||||
static __inline int32_t
|
||||
scsi_3btol(u_int8_t *bytes)
|
||||
{
|
||||
u_int32_t rc = scsi_3btoul(bytes);
|
||||
|
||||
if (rc & 0x00800000)
|
||||
rc |= 0xff000000;
|
||||
|
||||
return (int32_t) rc;
|
||||
}
|
||||
|
||||
static __inline u_int32_t
|
||||
scsi_4btoul(u_int8_t *bytes)
|
||||
{
|
||||
u_int32_t rv;
|
||||
|
||||
rv = (bytes[0] << 24) |
|
||||
(bytes[1] << 16) |
|
||||
(bytes[2] << 8) |
|
||||
bytes[3];
|
||||
return (rv);
|
||||
}
|
||||
__END_DECLS
|
||||
|
||||
#endif /*_SCSI_SCSI_ALL_H*/
|
3016
sys/cam/scsi/scsi_cd.c
Normal file
3016
sys/cam/scsi/scsi_cd.c
Normal file
File diff suppressed because it is too large
Load Diff
217
sys/cam/scsi/scsi_cd.h
Normal file
217
sys/cam/scsi/scsi_cd.h
Normal file
@ -0,0 +1,217 @@
|
||||
/*
|
||||
* Written by Julian Elischer (julian@tfs.com)
|
||||
* for TRW Financial Systems.
|
||||
*
|
||||
* TRW Financial Systems, in accordance with their agreement with Carnegie
|
||||
* Mellon University, makes this software available to CMU to distribute
|
||||
* or use in any manner that they see fit as long as this message is kept with
|
||||
* the software. For this reason TFS also grants any other persons or
|
||||
* organisations permission to use or modify this software.
|
||||
*
|
||||
* TFS supplies this software to be publicly redistributed
|
||||
* on the understanding that TFS is not responsible for the correct
|
||||
* functioning of this software in any circumstances.
|
||||
*
|
||||
* Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
|
||||
*
|
||||
* from: scsi_cd.h,v 1.10 1997/02/22 09:44:28 peter Exp $
|
||||
*/
|
||||
#ifndef _SCSI_SCSI_CD_H
|
||||
#define _SCSI_SCSI_CD_H 1
|
||||
|
||||
/*
|
||||
* Define two bits always in the same place in byte 2 (flag byte)
|
||||
*/
|
||||
#define CD_RELADDR 0x01
|
||||
#define CD_MSF 0x02
|
||||
|
||||
/*
|
||||
* SCSI command format
|
||||
*/
|
||||
|
||||
struct scsi_pause
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char unused[6];
|
||||
u_char resume;
|
||||
u_char control;
|
||||
};
|
||||
#define PA_PAUSE 1
|
||||
#define PA_RESUME 0
|
||||
|
||||
struct scsi_play_msf
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char unused;
|
||||
u_char start_m;
|
||||
u_char start_s;
|
||||
u_char start_f;
|
||||
u_char end_m;
|
||||
u_char end_s;
|
||||
u_char end_f;
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_play_track
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char unused[2];
|
||||
u_char start_track;
|
||||
u_char start_index;
|
||||
u_char unused1;
|
||||
u_char end_track;
|
||||
u_char end_index;
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_play
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char blk_addr[4];
|
||||
u_char unused;
|
||||
u_char xfer_len[2];
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_play_big
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2; /* same as above */
|
||||
u_char blk_addr[4];
|
||||
u_char xfer_len[4];
|
||||
u_char unused;
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_play_rel_big
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2; /* same as above */
|
||||
u_char blk_addr[4];
|
||||
u_char xfer_len[4];
|
||||
u_char track;
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_read_header
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char blk_addr[4];
|
||||
u_char unused;
|
||||
u_char data_len[2];
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_read_subchannel
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte1;
|
||||
u_char byte2;
|
||||
#define SRS_SUBQ 0x40
|
||||
u_char subchan_format;
|
||||
u_char unused[2];
|
||||
u_char track;
|
||||
u_char data_len[2];
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_read_toc
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char unused[4];
|
||||
u_char from_track;
|
||||
u_char data_len[2];
|
||||
u_char control;
|
||||
};
|
||||
;
|
||||
|
||||
struct scsi_read_cd_capacity
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char addr_3; /* Most Significant */
|
||||
u_char addr_2;
|
||||
u_char addr_1;
|
||||
u_char addr_0; /* Least Significant */
|
||||
u_char unused[3];
|
||||
u_char control;
|
||||
};
|
||||
|
||||
/*
|
||||
* Opcodes
|
||||
*/
|
||||
|
||||
#define READ_CD_CAPACITY 0x25 /* slightly different from disk */
|
||||
#define READ_SUBCHANNEL 0x42 /* cdrom read Subchannel */
|
||||
#define READ_TOC 0x43 /* cdrom read TOC */
|
||||
#define READ_HEADER 0x44 /* cdrom read header */
|
||||
#define PLAY 0x45 /* cdrom play 'play audio' mode */
|
||||
#define PLAY_MSF 0x47 /* cdrom play Min,Sec,Frames mode */
|
||||
#define PLAY_TRACK 0x48 /* cdrom play track/index mode */
|
||||
#define PLAY_TRACK_REL 0x49 /* cdrom play track/index mode */
|
||||
#define PAUSE 0x4b /* cdrom pause in 'play audio' mode */
|
||||
#define PLAY_BIG 0xa5 /* cdrom pause in 'play audio' mode */
|
||||
#define PLAY_TRACK_REL_BIG 0xa9 /* cdrom play track/index mode */
|
||||
|
||||
|
||||
|
||||
struct scsi_read_cd_cap_data
|
||||
{
|
||||
u_char addr_3; /* Most significant */
|
||||
u_char addr_2;
|
||||
u_char addr_1;
|
||||
u_char addr_0; /* Least significant */
|
||||
u_char length_3; /* Most significant */
|
||||
u_char length_2;
|
||||
u_char length_1;
|
||||
u_char length_0; /* Least significant */
|
||||
};
|
||||
|
||||
union cd_pages
|
||||
{
|
||||
struct audio_page
|
||||
{
|
||||
u_char page_code;
|
||||
#define CD_PAGE_CODE 0x3F
|
||||
#define AUDIO_PAGE 0x0e
|
||||
#define CD_PAGE_PS 0x80
|
||||
u_char param_len;
|
||||
u_char flags;
|
||||
#define CD_PA_SOTC 0x02
|
||||
#define CD_PA_IMMED 0x04
|
||||
u_char unused[2];
|
||||
u_char format_lba;
|
||||
#define CD_PA_FORMAT_LBA 0x0F
|
||||
#define CD_PA_APR_VALID 0x80
|
||||
u_char lb_per_sec[2];
|
||||
struct port_control
|
||||
{
|
||||
u_char channels;
|
||||
#define CHANNEL 0x0F
|
||||
#define CHANNEL_0 1
|
||||
#define CHANNEL_1 2
|
||||
#define CHANNEL_2 4
|
||||
#define CHANNEL_3 8
|
||||
#define LEFT_CHANNEL CHANNEL_0
|
||||
#define RIGHT_CHANNEL CHANNEL_1
|
||||
u_char volume;
|
||||
} port[4];
|
||||
#define LEFT_PORT 0
|
||||
#define RIGHT_PORT 1
|
||||
}audio;
|
||||
};
|
||||
|
||||
struct cd_mode_data
|
||||
{
|
||||
struct scsi_mode_header_6 header;
|
||||
struct scsi_mode_blk_desc blk_desc;
|
||||
union cd_pages page;
|
||||
};
|
||||
#endif /*_SCSI_SCSI_CD_H*/
|
||||
|
1584
sys/cam/scsi/scsi_ch.c
Normal file
1584
sys/cam/scsi/scsi_ch.c
Normal file
File diff suppressed because it is too large
Load Diff
486
sys/cam/scsi/scsi_ch.h
Normal file
486
sys/cam/scsi/scsi_ch.h
Normal file
@ -0,0 +1,486 @@
|
||||
/* $NetBSD: scsi_changer.h,v 1.11 1998/02/13 08:28:32 enami Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1996 Jason R. Thorpe <thorpej@and.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Partially based on an autochanger driver written by Stefan Grefen
|
||||
* and on an autochanger driver written by the Systems Programming Group
|
||||
* at the University of Utah Computer Science Department.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgements:
|
||||
* This product includes software developed by Jason R. Thorpe
|
||||
* for And Communications, http://www.and.com/
|
||||
* 4. 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* SCSI changer interface description
|
||||
*/
|
||||
|
||||
/*
|
||||
* Partially derived from software written by Stefan Grefen
|
||||
* (grefen@goofy.zdv.uni-mainz.de soon grefen@convex.com)
|
||||
* based on the SCSI System by written Julian Elischer (julian@tfs.com)
|
||||
* for TRW Financial Systems.
|
||||
*
|
||||
* TRW Financial Systems, in accordance with their agreement with Carnegie
|
||||
* Mellon University, makes this software available to CMU to distribute
|
||||
* or use in any manner that they see fit as long as this message is kept with
|
||||
* the software. For this reason TFS also grants any other persons or
|
||||
* organisations permission to use or modify this software.
|
||||
*
|
||||
* TFS supplies this software to be publicly redistributed
|
||||
* on the understanding that TFS is not responsible for the correct
|
||||
* functioning of this software in any circumstances.
|
||||
*
|
||||
* Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
|
||||
*/
|
||||
|
||||
#ifndef _SCSI_SCSI_CH_H
|
||||
#define _SCSI_SCSI_CH_H 1
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
/*
|
||||
* SCSI command format
|
||||
*/
|
||||
|
||||
/*
|
||||
* Exchange the medium in the source element with the medium
|
||||
* located at the destination element.
|
||||
*/
|
||||
struct scsi_exchange_medium {
|
||||
u_int8_t opcode;
|
||||
#define EXCHANGE_MEDIUM 0xa6
|
||||
u_int8_t byte2;
|
||||
u_int8_t tea[2]; /* transport element address */
|
||||
u_int8_t src[2]; /* source address */
|
||||
u_int8_t fdst[2]; /* first destination address */
|
||||
u_int8_t sdst[2]; /* second destination address */
|
||||
u_int8_t invert;
|
||||
#define EXCHANGE_MEDIUM_INV1 0x01
|
||||
#define EXCHANGE_MEDIUM_INV2 0x02
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
/*
|
||||
* Cause the medium changer to check all elements for medium and any
|
||||
* other status relevant to the element.
|
||||
*/
|
||||
struct scsi_initialize_element_status {
|
||||
u_int8_t opcode;
|
||||
#define INITIALIZE_ELEMENT_STATUS 0x07
|
||||
u_int8_t byte2;
|
||||
u_int8_t reserved[3];
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
/*
|
||||
* Request the changer to move a unit of media from the source element
|
||||
* to the destination element.
|
||||
*/
|
||||
struct scsi_move_medium {
|
||||
u_int8_t opcode;
|
||||
#define MOVE_MEDIUM 0xa5
|
||||
u_int8_t byte2;
|
||||
u_int8_t tea[2]; /* transport element address */
|
||||
u_int8_t src[2]; /* source element address */
|
||||
u_int8_t dst[2]; /* destination element address */
|
||||
u_int8_t reserved[2];
|
||||
u_int8_t invert;
|
||||
#define MOVE_MEDIUM_INVERT 0x01
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
/*
|
||||
* Position the specified transport element (picker) in front of
|
||||
* the destination element specified.
|
||||
*/
|
||||
struct scsi_position_to_element {
|
||||
u_int8_t opcode;
|
||||
#define POSITION_TO_ELEMENT 0x2b
|
||||
u_int8_t byte2;
|
||||
u_int8_t tea[2]; /* transport element address */
|
||||
u_int8_t dst[2]; /* destination element address */
|
||||
u_int8_t reserved[2];
|
||||
u_int8_t invert;
|
||||
#define POSITION_TO_ELEMENT_INVERT 0x01
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
/*
|
||||
* Request that the changer report the status of its internal elements.
|
||||
*/
|
||||
struct scsi_read_element_status {
|
||||
u_int8_t opcode;
|
||||
#define READ_ELEMENT_STATUS 0xb8
|
||||
u_int8_t byte2;
|
||||
#define READ_ELEMENT_STATUS_VOLTAG 0x10 /* report volume tag info */
|
||||
/* ...next 4 bits are an element type code... */
|
||||
u_int8_t sea[2]; /* starting element address */
|
||||
u_int8_t count[2]; /* number of elements */
|
||||
u_int8_t reserved0;
|
||||
u_int8_t len[3]; /* length of data buffer */
|
||||
u_int8_t reserved1;
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
struct scsi_request_volume_element_address {
|
||||
u_int8_t opcode;
|
||||
#define REQUEST_VOLUME_ELEMENT_ADDRESS 0xb5
|
||||
u_int8_t byte2;
|
||||
#define REQUEST_VOLUME_ELEMENT_ADDRESS_VOLTAG 0x10
|
||||
/* ...next 4 bits are an element type code... */
|
||||
u_int8_t eaddr[2]; /* element address */
|
||||
u_int8_t count[2]; /* number of elements */
|
||||
u_int8_t reserved0;
|
||||
u_int8_t len[3]; /* length of data buffer */
|
||||
u_int8_t reserved1;
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
/* XXX scsi_release */
|
||||
|
||||
/*
|
||||
* Changer-specific mode page numbers.
|
||||
*/
|
||||
#define CH_ELEMENT_ADDR_ASSIGN_PAGE 0x1D
|
||||
#define CH_TRANS_GEOM_PARAMS_PAGE 0x1E
|
||||
#define CH_DEVICE_CAP_PAGE 0x1F
|
||||
|
||||
/*
|
||||
* Data returned by READ ELEMENT STATUS consists of an 8-byte header
|
||||
* followed by one or more read_element_status_pages.
|
||||
*/
|
||||
struct read_element_status_header {
|
||||
u_int8_t fear[2]; /* first element address reported */
|
||||
u_int8_t count[2]; /* number of elements available */
|
||||
u_int8_t reserved;
|
||||
u_int8_t nbytes[3]; /* byte count of all pages */
|
||||
};
|
||||
|
||||
struct read_element_status_page_header {
|
||||
u_int8_t type; /* element type code; see type codes below */
|
||||
u_int8_t flags;
|
||||
#define READ_ELEMENT_STATUS_AVOLTAG 0x40
|
||||
#define READ_ELEMENT_STATUS_PVOLTAG 0x80
|
||||
u_int8_t edl[2]; /* element descriptor length */
|
||||
u_int8_t reserved;
|
||||
u_int8_t nbytes[3]; /* byte count of all descriptors */
|
||||
};
|
||||
|
||||
/*
|
||||
* Format of a volume tag
|
||||
*/
|
||||
|
||||
struct volume_tag {
|
||||
u_int8_t vif[32]; /* volume identification field */
|
||||
u_int8_t reserved[2];
|
||||
u_int8_t vsn[2]; /* volume sequence number */
|
||||
};
|
||||
|
||||
struct read_element_status_descriptor {
|
||||
u_int8_t eaddr[2]; /* element address */
|
||||
u_int8_t flags1;
|
||||
|
||||
#define READ_ELEMENT_STATUS_FULL 0x01
|
||||
#define READ_ELEMENT_STATUS_IMPEXP 0x02
|
||||
#define READ_ELEMENT_STATUS_EXCEPT 0x04
|
||||
#define READ_ELEMENT_STATUS_ACCESS 0x08
|
||||
#define READ_ELEMENT_STATUS_EXENAB 0x10
|
||||
#define READ_ELEMENT_STATUS_INENAB 0x20
|
||||
|
||||
#define READ_ELEMENT_STATUS_MT_MASK1 0x05
|
||||
#define READ_ELEMENT_STATUS_ST_MASK1 0x0c
|
||||
#define READ_ELEMENT_STATUS_IE_MASK1 0x3f
|
||||
#define READ_ELEMENT_STATUS_DT_MASK1 0x0c
|
||||
|
||||
u_int8_t reserved0;
|
||||
u_int8_t sense_code;
|
||||
u_int8_t sense_qual;
|
||||
|
||||
/*
|
||||
* dt_scsi_flags and dt_scsi_addr are valid only on data transport
|
||||
* elements. These bytes are undefined for all other element types.
|
||||
*/
|
||||
u_int8_t dt_scsi_flags;
|
||||
|
||||
#define READ_ELEMENT_STATUS_DT_LUNMASK 0x07
|
||||
#define READ_ELEMENT_STATUS_DT_LUVALID 0x10
|
||||
#define READ_ELEMENT_STATUS_DT_IDVALID 0x20
|
||||
#define READ_ELEMENT_STATUS_DT_NOTBUS 0x80
|
||||
|
||||
u_int8_t dt_scsi_addr;
|
||||
|
||||
u_int8_t reserved1;
|
||||
|
||||
u_int8_t flags2;
|
||||
#define READ_ELEMENT_STATUS_INVERT 0x40
|
||||
#define READ_ELEMENT_STATUS_SVALID 0x80
|
||||
u_int8_t ssea[2]; /* source storage element address */
|
||||
|
||||
struct volume_tag pvoltag; /* omitted if PVOLTAG == 0 */
|
||||
struct volume_tag avoltag; /* omitted if AVOLTAG == 0 */
|
||||
|
||||
/* Other data may follow */
|
||||
};
|
||||
|
||||
/* XXX add data returned by REQUEST VOLUME ELEMENT ADDRESS */
|
||||
|
||||
/* Element type codes */
|
||||
#define ELEMENT_TYPE_MASK 0x0f /* Note: these aren't bits */
|
||||
#define ELEMENT_TYPE_ALL 0x00
|
||||
#define ELEMENT_TYPE_MT 0x01
|
||||
#define ELEMENT_TYPE_ST 0x02
|
||||
#define ELEMENT_TYPE_IE 0x03
|
||||
#define ELEMENT_TYPE_DT 0x04
|
||||
|
||||
/*
|
||||
* XXX The following definitions should be common to all SCSI device types.
|
||||
*/
|
||||
#define PGCODE_MASK 0x3f /* valid page number bits in pg_code */
|
||||
#define PGCODE_PS 0x80 /* indicates page is savable */
|
||||
|
||||
/*
|
||||
* Send volume tag information to the changer
|
||||
*/
|
||||
|
||||
struct scsi_send_volume_tag {
|
||||
u_int8_t opcode;
|
||||
#define SEND_VOLUME_TAG 0xb6
|
||||
u_int8_t byte2;
|
||||
u_int8_t ea[2]; /* element address */
|
||||
u_int8_t reserved2;
|
||||
u_int8_t sac; /* send action code */
|
||||
|
||||
#define SEND_VOLUME_TAG_ASSERT_PRIMARY 0x08
|
||||
#define SEND_VOLUME_TAG_ASSERT_ALTERNATE 0x09
|
||||
#define SEND_VOLUME_TAG_REPLACE_PRIMARY 0x0a
|
||||
#define SEND_VOLUME_TAG_REPLACE_ALTERNATE 0x0b
|
||||
#define SEND_VOLUME_TAG_UNDEFINED_PRIMARY 0x0c
|
||||
#define SEND_VOLUME_TAG_UNDEFINED_ALTERNATE 0x0d
|
||||
|
||||
u_int8_t reserved4[2];
|
||||
u_int8_t pll[2]; /* parameter list length */
|
||||
u_int8_t reserved5;
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
/*
|
||||
* Parameter format for SEND VOLUME TAG
|
||||
*/
|
||||
|
||||
struct scsi_send_volume_tag_parameters {
|
||||
u_int8_t vitf[32]; /* volume tag identification template */
|
||||
u_int8_t reserved1[2];
|
||||
u_int8_t minvsn[2]; /* minimum volume sequence number */
|
||||
u_int8_t reserved2[2];
|
||||
u_int8_t maxvsn[2]; /* maximum volume sequence number */
|
||||
};
|
||||
|
||||
/*
|
||||
* Device capabilities page.
|
||||
*
|
||||
* This page defines characteristics of the elemenet types in the
|
||||
* medium changer device.
|
||||
*
|
||||
* Note in the definitions below, the following abbreviations are
|
||||
* used:
|
||||
* MT Medium transport element (picker)
|
||||
* ST Storage transport element (slot)
|
||||
* IE Import/export element (portal)
|
||||
* DT Data tranfer element (tape/disk drive)
|
||||
*/
|
||||
struct page_device_capabilities {
|
||||
u_int8_t pg_code; /* page code (0x1f) */
|
||||
u_int8_t pg_length; /* page length (0x12) */
|
||||
|
||||
/*
|
||||
* The STOR_xx bits indicate that an element of a given
|
||||
* type may provide independent storage for a unit of
|
||||
* media. The top four bits of this value are reserved.
|
||||
*/
|
||||
u_int8_t stor;
|
||||
#define STOR_MT 0x01
|
||||
#define STOR_ST 0x02
|
||||
#define STOR_IE 0x04
|
||||
#define STOR_DT 0x08
|
||||
|
||||
u_int8_t reserved0;
|
||||
|
||||
/*
|
||||
* The MOVE_TO_yy bits indicate the changer supports
|
||||
* moving a unit of medium from an element of a given type to an
|
||||
* element of type yy. This is used to determine if a given
|
||||
* MOVE MEDIUM command is legal. The top four bits of each
|
||||
* of these values are reserved.
|
||||
*/
|
||||
u_int8_t move_from_mt;
|
||||
u_int8_t move_from_st;
|
||||
u_int8_t move_from_ie;
|
||||
u_int8_t move_from_dt;
|
||||
#define MOVE_TO_MT 0x01
|
||||
#define MOVE_TO_ST 0x02
|
||||
#define MOVE_TO_IE 0x04
|
||||
#define MOVE_TO_DT 0x08
|
||||
|
||||
u_int8_t reserved1[2];
|
||||
|
||||
/*
|
||||
* Similar to above, but for EXCHANGE MEDIUM.
|
||||
*/
|
||||
u_int8_t exchange_with_mt;
|
||||
u_int8_t exchange_with_st;
|
||||
u_int8_t exchange_with_ie;
|
||||
u_int8_t exchange_with_dt;
|
||||
#define EXCHANGE_WITH_MT 0x01
|
||||
#define EXCHANGE_WITH_ST 0x02
|
||||
#define EXCHANGE_WITH_IE 0x04
|
||||
#define EXCHANGE_WITH_DT 0x08
|
||||
};
|
||||
|
||||
/*
|
||||
* Medium changer elemement address assignment page.
|
||||
*
|
||||
* Some of these fields can be a little confusing, so an explanation
|
||||
* is in order.
|
||||
*
|
||||
* Each component within a a medium changer apparatus is called an
|
||||
* "element".
|
||||
*
|
||||
* The "medium transport element address" is the address of the first
|
||||
* picker (robotic arm). "Number of medium transport elements" tells
|
||||
* us how many pickers exist in the changer.
|
||||
*
|
||||
* The "first storage element address" is the address of the first
|
||||
* slot in the tape or disk magazine. "Number of storage elements" tells
|
||||
* us how many slots exist in the changer.
|
||||
*
|
||||
* The "first import/export element address" is the address of the first
|
||||
* medium portal accessible both by the medium changer and an outside
|
||||
* human operator. This is where the changer might deposit tapes destined
|
||||
* for some vault. The "number of import/export elements" tells us
|
||||
* not many of these portals exist in the changer. NOTE: this number may
|
||||
* be 0.
|
||||
*
|
||||
* The "first data transfer element address" is the address of the first
|
||||
* tape or disk drive in the changer. "Number of data transfer elements"
|
||||
* tells us how many drives exist in the changer.
|
||||
*/
|
||||
struct page_element_address_assignment {
|
||||
u_int8_t pg_code; /* page code (0x1d) */
|
||||
u_int8_t pg_length; /* page length (0x12) */
|
||||
|
||||
/* Medium transport element address */
|
||||
u_int8_t mtea[2];
|
||||
|
||||
/* Number of medium transport elements */
|
||||
u_int8_t nmte[2];
|
||||
|
||||
/* First storage element address */
|
||||
u_int8_t fsea[2];
|
||||
|
||||
/* Number of storage elements */
|
||||
u_int8_t nse[2];
|
||||
|
||||
/* First import/export element address */
|
||||
u_int8_t fieea[2];
|
||||
|
||||
/* Number of import/export elements */
|
||||
u_int8_t niee[2];
|
||||
|
||||
/* First data transfer element address */
|
||||
u_int8_t fdtea[2];
|
||||
|
||||
/* Number of data trafer elements */
|
||||
u_int8_t ndte[2];
|
||||
|
||||
u_int8_t reserved[2];
|
||||
};
|
||||
|
||||
/*
|
||||
* Transport geometry parameters page.
|
||||
*
|
||||
* Defines whether each medium transport element is a member of a set of
|
||||
* elements that share a common robotics subsystem and whether the element
|
||||
* is capable of media rotation. One transport geometry descriptor is
|
||||
* transferred for each medium transport element, beginning with the first
|
||||
* medium transport element (other than the default transport element address
|
||||
* of 0).
|
||||
*/
|
||||
struct page_transport_geometry_parameters {
|
||||
u_int8_t pg_code; /* page code (0x1e) */
|
||||
u_int8_t pg_length; /* page length; variable */
|
||||
|
||||
/* Transport geometry descriptor(s) are here. */
|
||||
|
||||
u_int8_t misc;
|
||||
#define CAN_ROTATE 0x01
|
||||
|
||||
/* Member number in transport element set. */
|
||||
u_int8_t member;
|
||||
};
|
||||
|
||||
__BEGIN_DECLS
|
||||
void scsi_move_medium(struct ccb_scsiio *csio, u_int32_t retries,
|
||||
void (*cbfcnp)(struct cam_periph *, union ccb *),
|
||||
u_int8_t tag_action, u_int32_t tea, u_int32_t src,
|
||||
u_int32_t dst, int invert, u_int8_t sense_len,
|
||||
u_int32_t timeout);
|
||||
|
||||
void scsi_exchange_medium(struct ccb_scsiio *csio, u_int32_t retries,
|
||||
void (*cbfcnp)(struct cam_periph *, union ccb *),
|
||||
u_int8_t tag_action, u_int32_t tea, u_int32_t src,
|
||||
u_int32_t dst1, u_int32_t dst2, int invert1,
|
||||
int invert2, u_int8_t sense_len, u_int32_t timeout);
|
||||
|
||||
void scsi_position_to_element(struct ccb_scsiio *csio, u_int32_t retries,
|
||||
void (*cbfcnp)(struct cam_periph *, union ccb *),
|
||||
u_int8_t tag_action, u_int32_t tea, u_int32_t dst,
|
||||
int invert, u_int8_t sense_len,
|
||||
u_int32_t timeout);
|
||||
|
||||
void scsi_read_element_status(struct ccb_scsiio *csio, u_int32_t retries,
|
||||
void (*cbfcnp)(struct cam_periph *, union ccb *),
|
||||
u_int8_t tag_action, int voltag, u_int32_t sea,
|
||||
u_int32_t count, u_int8_t *data_ptr,
|
||||
u_int32_t dxfer_len, u_int8_t sense_len,
|
||||
u_int32_t timeout);
|
||||
|
||||
void scsi_initialize_element_status(struct ccb_scsiio *csio, u_int32_t retries,
|
||||
void (*cbfcnp)(struct cam_periph *, union ccb *),
|
||||
u_int8_t tag_action, u_int8_t sense_len,
|
||||
u_int32_t timeout);
|
||||
void scsi_send_volume_tag(struct ccb_scsiio *csio, u_int32_t retries,
|
||||
void (*cbfcnp)(struct cam_periph *, union ccb *),
|
||||
u_int8_t tag_action,
|
||||
u_int16_t element_address,
|
||||
u_int8_t send_action_code,
|
||||
struct scsi_send_volume_tag_parameters *parameters,
|
||||
u_int8_t sense_len, u_int32_t timeout);
|
||||
__END_DECLS
|
||||
|
||||
#endif /* _SCSI_SCSI_CH_H */
|
1520
sys/cam/scsi/scsi_da.c
Normal file
1520
sys/cam/scsi/scsi_da.c
Normal file
File diff suppressed because it is too large
Load Diff
391
sys/cam/scsi/scsi_da.h
Normal file
391
sys/cam/scsi/scsi_da.h
Normal file
@ -0,0 +1,391 @@
|
||||
/*
|
||||
* Structures and definitions for SCSI commands to Direct Access Devices
|
||||
*/
|
||||
|
||||
/*
|
||||
* Some lines of this file come from a file of the name "scsi.h"
|
||||
* distributed by OSF as part of mach2.5,
|
||||
* so the following disclaimer has been kept.
|
||||
*
|
||||
* Copyright 1990 by Open Software Foundation,
|
||||
* Grenoble, FRANCE
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software and
|
||||
* its documentation for any purpose and without fee is hereby granted,
|
||||
* provided that the above copyright notice appears in all copies and
|
||||
* that both the copyright notice and this permission notice appear in
|
||||
* supporting documentation, and that the name of OSF or Open Software
|
||||
* Foundation not be used in advertising or publicity pertaining to
|
||||
* distribution of the software without specific, written prior
|
||||
* permission.
|
||||
*
|
||||
* OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
|
||||
* IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||||
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Largely written by Julian Elischer (julian@tfs.com)
|
||||
* for TRW Financial Systems.
|
||||
*
|
||||
* TRW Financial Systems, in accordance with their agreement with Carnegie
|
||||
* Mellon University, makes this software available to CMU to distribute
|
||||
* or use in any manner that they see fit as long as this message is kept with
|
||||
* the software. For this reason TFS also grants any other persons or
|
||||
* organisations permission to use or modify this software.
|
||||
*
|
||||
* TFS supplies this software to be publicly redistributed
|
||||
* on the understanding that TFS is not responsible for the correct
|
||||
* functioning of this software in any circumstances.
|
||||
*
|
||||
* Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef _SCSI_SCSI_DA_H
|
||||
#define _SCSI_SCSI_DA_H 1
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
struct scsi_rezero_unit
|
||||
{
|
||||
u_int8_t opcode;
|
||||
#define SRZU_LUN_MASK 0xE0
|
||||
u_int8_t byte2;
|
||||
u_int8_t reserved[3];
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
struct scsi_reassign_blocks
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t byte2;
|
||||
u_int8_t unused[3];
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
struct scsi_rw_6
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t addr[3];
|
||||
/* only 5 bits are valid in the MSB address byte */
|
||||
#define SRW_TOPADDR 0x1F
|
||||
u_int8_t length;
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
struct scsi_rw_10
|
||||
{
|
||||
u_int8_t opcode;
|
||||
#define SRW10_RELADDR 0x01
|
||||
#define SRW10_FUA 0x08
|
||||
#define SRW10_DPO 0x10
|
||||
u_int8_t byte2;
|
||||
u_int8_t addr[4];
|
||||
u_int8_t reserved;
|
||||
u_int8_t length[2];
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
struct scsi_rw_12
|
||||
{
|
||||
u_int8_t opcode;
|
||||
#define SRW12_RELADDR 0x01
|
||||
#define SRW12_FUA 0x08
|
||||
#define SRW12_DPO 0x10
|
||||
u_int8_t byte2;
|
||||
u_int8_t addr[4];
|
||||
u_int8_t reserved;
|
||||
u_int8_t length[4];
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
struct scsi_start_stop_unit
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t byte2;
|
||||
#define SSS_IMMED 0x01
|
||||
u_int8_t reserved[2];
|
||||
u_int8_t how;
|
||||
#define SSS_START 0x01
|
||||
#define SSS_LOEJ 0x02
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
struct scsi_read_defect_data_10
|
||||
{
|
||||
u_int8_t opcode;
|
||||
|
||||
/*
|
||||
* The most significant 3 bits are the LUN, the other 5 are
|
||||
* reserved.
|
||||
*/
|
||||
#define SRDD10_LUN_MASK 0xE0
|
||||
u_int8_t byte2;
|
||||
#define SRDD10_GLIST 0x08
|
||||
#define SRDD10_PLIST 0x10
|
||||
#define SRDD10_DLIST_FORMAT_MASK 0x07
|
||||
#define SRDD10_BLOCK_FORMAT 0x00
|
||||
#define SRDD10_BYTES_FROM_INDEX_FORMAT 0x04
|
||||
#define SRDD10_PHYSICAL_SECTOR_FORMAT 0x05
|
||||
u_int8_t format;
|
||||
|
||||
u_int8_t reserved[4];
|
||||
|
||||
u_int8_t alloc_length[2];
|
||||
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
struct scsi_read_defect_data_12
|
||||
{
|
||||
u_int8_t opcode;
|
||||
|
||||
/*
|
||||
* The most significant 3 bits are the LUN, the other 5 are
|
||||
* reserved.
|
||||
*/
|
||||
#define SRDD12_LUN_MASK 0xE0
|
||||
u_int8_t byte2;
|
||||
|
||||
#define SRDD12_GLIST 0x08
|
||||
#define SRDD12_PLIST 0x10
|
||||
#define SRDD12_DLIST_FORMAT_MASK 0x07
|
||||
#define SRDD12_BLOCK_FORMAT 0x00
|
||||
#define SRDD12_BYTES_FROM_INDEX_FORMAT 0x04
|
||||
#define SRDD12_PHYSICAL_SECTOR_FORMAT 0x05
|
||||
u_int8_t format;
|
||||
|
||||
u_int8_t reserved[4];
|
||||
|
||||
u_int8_t alloc_length[4];
|
||||
|
||||
u_int8_t control;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Opcodes
|
||||
*/
|
||||
#define REZERO_UNIT 0x01
|
||||
#define REASSIGN_BLOCKS 0x07
|
||||
#define READ_6 0x08
|
||||
#define WRITE_6 0x0a
|
||||
#define MODE_SELECT 0x15
|
||||
#define MODE_SENSE 0x1a
|
||||
#define START_STOP_UNIT 0x1b
|
||||
#define READ_10 0x28
|
||||
#define WRITE_10 0x2a
|
||||
#define READ_DEFECT_DATA_10 0x37
|
||||
#define READ_12 0xa8
|
||||
#define WRITE_12 0xaa
|
||||
#define READ_DEFECT_DATA_12 0xb7
|
||||
|
||||
|
||||
struct scsi_reassign_blocks_data
|
||||
{
|
||||
u_int8_t reserved[2];
|
||||
u_int8_t length[2];
|
||||
struct {
|
||||
u_int8_t dlbaddr[4]; /* defect logical block address */
|
||||
} defect_descriptor[1];
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* This is the list header for the READ DEFECT DATA(10) command above.
|
||||
* It may be a bit wrong to append the 10 at the end of the data structure,
|
||||
* since it's only 4 bytes but it does tie it to the 10 byte command.
|
||||
*/
|
||||
struct scsi_read_defect_data_hdr_10
|
||||
{
|
||||
u_int8_t reserved;
|
||||
#define SRDDH10_GLIST 0x08
|
||||
#define SRDDH10_PLIST 0x10
|
||||
#define SRDDH10_DLIST_FORMAT_MASK 0x07
|
||||
#define SRDDH10_BLOCK_FORMAT 0x00
|
||||
#define SRDDH10_BYTES_FROM_INDEX_FORMAT 0x04
|
||||
#define SRDDH10_PHYSICAL_SECTOR_FORMAT 0x05
|
||||
u_int8_t format;
|
||||
u_int8_t length[2];
|
||||
};
|
||||
|
||||
struct scsi_defect_desc_block
|
||||
{
|
||||
u_int8_t address[4];
|
||||
};
|
||||
|
||||
struct scsi_defect_desc_bytes_from_index
|
||||
{
|
||||
u_int8_t cylinder[3];
|
||||
u_int8_t head;
|
||||
u_int8_t bytes_from_index[4];
|
||||
};
|
||||
|
||||
struct scsi_defect_desc_phys_sector
|
||||
{
|
||||
u_int8_t cylinder[3];
|
||||
u_int8_t head;
|
||||
u_int8_t sector[4];
|
||||
};
|
||||
|
||||
struct scsi_read_defect_data_hdr_12
|
||||
{
|
||||
u_int8_t reserved;
|
||||
#define SRDDH12_GLIST 0x08
|
||||
#define SRDDH12_PLIST 0x10
|
||||
#define SRDDH12_DLIST_FORMAT_MASK 0x07
|
||||
#define SRDDH12_BLOCK_FORMAT 0x00
|
||||
#define SRDDH12_BYTES_FROM_INDEX_FORMAT 0x04
|
||||
#define SRDDH12_PHYSICAL_SECTOR_FORMAT 0x05
|
||||
u_int8_t format;
|
||||
u_int8_t length[4];
|
||||
};
|
||||
|
||||
union disk_pages /* this is the structure copied from osf */
|
||||
{
|
||||
struct format_device_page {
|
||||
u_int8_t pg_code; /* page code (should be 3) */
|
||||
#define SMS_FORMAT_DEVICE_PAGE 0x03 /* only 6 bits valid */
|
||||
u_int8_t pg_length; /* page length (should be 0x16) */
|
||||
#define SMS_FORMAT_DEVICE_PLEN 0x16
|
||||
u_int8_t trk_z_1; /* tracks per zone (MSB) */
|
||||
u_int8_t trk_z_0; /* tracks per zone (LSB) */
|
||||
u_int8_t alt_sec_1; /* alternate sectors per zone (MSB) */
|
||||
u_int8_t alt_sec_0; /* alternate sectors per zone (LSB) */
|
||||
u_int8_t alt_trk_z_1; /* alternate tracks per zone (MSB) */
|
||||
u_int8_t alt_trk_z_0; /* alternate tracks per zone (LSB) */
|
||||
u_int8_t alt_trk_v_1; /* alternate tracks per volume (MSB) */
|
||||
u_int8_t alt_trk_v_0; /* alternate tracks per volume (LSB) */
|
||||
u_int8_t ph_sec_t_1; /* physical sectors per track (MSB) */
|
||||
u_int8_t ph_sec_t_0; /* physical sectors per track (LSB) */
|
||||
u_int8_t bytes_s_1; /* bytes per sector (MSB) */
|
||||
u_int8_t bytes_s_0; /* bytes per sector (LSB) */
|
||||
u_int8_t interleave_1; /* interleave (MSB) */
|
||||
u_int8_t interleave_0; /* interleave (LSB) */
|
||||
u_int8_t trk_skew_1; /* track skew factor (MSB) */
|
||||
u_int8_t trk_skew_0; /* track skew factor (LSB) */
|
||||
u_int8_t cyl_skew_1; /* cylinder skew (MSB) */
|
||||
u_int8_t cyl_skew_0; /* cylinder skew (LSB) */
|
||||
u_int8_t flags; /* various */
|
||||
#define DISK_FMT_SURF 0x10
|
||||
#define DISK_FMT_RMB 0x20
|
||||
#define DISK_FMT_HSEC 0x40
|
||||
#define DISK_FMT_SSEC 0x80
|
||||
u_int8_t reserved21;
|
||||
u_int8_t reserved22;
|
||||
u_int8_t reserved23;
|
||||
} format_device;
|
||||
struct rigid_geometry_page {
|
||||
u_int8_t pg_code; /* page code (should be 4) */
|
||||
#define SMS_RIGID_GEOMETRY_PAGE 0x04
|
||||
u_int8_t pg_length; /* page length (should be 0x16) */
|
||||
#define SMS_RIGID_GEOMETRY_PLEN 0x16
|
||||
u_int8_t ncyl_2; /* number of cylinders (MSB) */
|
||||
u_int8_t ncyl_1; /* number of cylinders */
|
||||
u_int8_t ncyl_0; /* number of cylinders (LSB) */
|
||||
u_int8_t nheads; /* number of heads */
|
||||
u_int8_t st_cyl_wp_2; /* starting cyl., write precomp (MSB) */
|
||||
u_int8_t st_cyl_wp_1; /* starting cyl., write precomp */
|
||||
u_int8_t st_cyl_wp_0; /* starting cyl., write precomp (LSB) */
|
||||
u_int8_t st_cyl_rwc_2; /* starting cyl., red. write cur (MSB)*/
|
||||
u_int8_t st_cyl_rwc_1; /* starting cyl., red. write cur */
|
||||
u_int8_t st_cyl_rwc_0; /* starting cyl., red. write cur (LSB)*/
|
||||
u_int8_t driv_step_1; /* drive step rate (MSB) */
|
||||
u_int8_t driv_step_0; /* drive step rate (LSB) */
|
||||
u_int8_t land_zone_2; /* landing zone cylinder (MSB) */
|
||||
u_int8_t land_zone_1; /* landing zone cylinder */
|
||||
u_int8_t land_zone_0; /* landing zone cylinder (LSB) */
|
||||
u_int8_t rpl; /* rotational position locking (2 bits) */
|
||||
u_int8_t rot_offset; /* rotational offset */
|
||||
u_int8_t reserved19;
|
||||
u_int8_t medium_rot_rate_1; /* medium rotation rate (RPM) (MSB) */
|
||||
u_int8_t medium_rot_rate_0; /* medium rotation rate (RPM) (LSB) */
|
||||
u_int8_t reserved22;
|
||||
u_int8_t reserved23;
|
||||
} rigid_geometry;
|
||||
struct flexible_disk_page {
|
||||
u_int8_t pg_code; /* page code (should be 5) */
|
||||
#define SMS_FLEXIBLE_GEOMETRY_PAGE 0x05
|
||||
u_int8_t pg_length; /* page length (should be 0x1E) */
|
||||
#define SMS_FLEXIBLE_GEOMETRY_PLEN 0x0x1E
|
||||
u_int8_t xfr_rate_1; /* transfer rate (MSB) */
|
||||
u_int8_t xfr_rate_0; /* transfer rate (LSB) */
|
||||
u_int8_t nheads; /* number of heads */
|
||||
u_int8_t sec_per_track; /* Sectors per track */
|
||||
u_int8_t bytes_s_1; /* bytes per sector (MSB) */
|
||||
u_int8_t bytes_s_0; /* bytes per sector (LSB) */
|
||||
u_int8_t ncyl_1; /* number of cylinders (MSB) */
|
||||
u_int8_t ncyl_0; /* number of cylinders (LSB) */
|
||||
u_int8_t st_cyl_wp_1; /* starting cyl., write precomp (MSB) */
|
||||
u_int8_t st_cyl_wp_0; /* starting cyl., write precomp (LSB) */
|
||||
u_int8_t st_cyl_rwc_1; /* starting cyl., red. write cur (MSB)*/
|
||||
u_int8_t st_cyl_rwc_0; /* starting cyl., red. write cur (LSB)*/
|
||||
u_int8_t driv_step_1; /* drive step rate (MSB) */
|
||||
u_int8_t driv_step_0; /* drive step rate (LSB) */
|
||||
u_int8_t driv_step_pw; /* drive step pulse width */
|
||||
u_int8_t head_stl_del_1;/* Head settle delay (MSB) */
|
||||
u_int8_t head_stl_del_0;/* Head settle delay (LSB) */
|
||||
u_int8_t motor_on_del; /* Motor on delay */
|
||||
u_int8_t motor_off_del; /* Motor off delay */
|
||||
u_int8_t trdy_ssn_mo; /* XXX ??? */
|
||||
u_int8_t spc; /* XXX ??? */
|
||||
u_int8_t write_comp; /* Write compensation */
|
||||
u_int8_t head_load_del; /* Head load delay */
|
||||
u_int8_t head_uload_del;/* Head un-load delay */
|
||||
u_int8_t pin32_pin2;
|
||||
u_int8_t pin4_pint1;
|
||||
u_int8_t medium_rot_rate_1; /* medium rotation rate (RPM) (MSB) */
|
||||
u_int8_t medium_rot_rate_0; /* medium rotation rate (RPM) (LSB) */
|
||||
u_int8_t reserved30;
|
||||
u_int8_t reserved31;
|
||||
} flexible_disk;
|
||||
};
|
||||
|
||||
struct scsi_da_rw_recovery_page {
|
||||
u_int8_t page_code;
|
||||
#define SMS_RW_ERROR_RECOVERY_PAGE 0x01
|
||||
u_int8_t page_length;
|
||||
u_int8_t byte3;
|
||||
#define SMS_RWER_AWRE 0x80
|
||||
#define SMS_RWER_ARRE 0x40
|
||||
#define SMS_RWER_TB 0x20
|
||||
#define SMS_RWER_RC 0x10
|
||||
#define SMS_RWER_EER 0x08
|
||||
#define SMS_RWER_PER 0x04
|
||||
#define SMS_RWER_DTE 0x02
|
||||
#define SMS_RWER_DCR 0x01
|
||||
u_int8_t read_retry_count;
|
||||
u_int8_t correction_span;
|
||||
u_int8_t head_offset_count;
|
||||
u_int8_t data_strobe_offset_cnt;
|
||||
u_int8_t reserved;
|
||||
u_int8_t write_retry_count;
|
||||
u_int8_t reserved2;
|
||||
u_int8_t recovery_time_limit[2];
|
||||
};
|
||||
|
||||
__BEGIN_DECLS
|
||||
void scsi_read_write(struct ccb_scsiio *csio, u_int32_t retries,
|
||||
void (*cbfcnp)(struct cam_periph *, union ccb *),
|
||||
u_int8_t tag_action, int readop, u_int8_t byte2,
|
||||
int minimum_cmd_size, u_int32_t lba,
|
||||
u_int32_t block_count, u_int8_t *data_ptr,
|
||||
u_int32_t dxfer_len, u_int8_t sense_len,
|
||||
u_int32_t timeout);
|
||||
|
||||
void scsi_start_stop(struct ccb_scsiio *csio, u_int32_t retries,
|
||||
void (*cbfcnp)(struct cam_periph *, union ccb *),
|
||||
u_int8_t tag_action, int start, int load_eject,
|
||||
int immediate, u_int8_t sense_len, u_int32_t timeout);
|
||||
__END_DECLS
|
||||
|
||||
#endif /* _SCSI_SCSI_DA_H */
|
42
sys/cam/scsi/scsi_message.h
Normal file
42
sys/cam/scsi/scsi_message.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* Messages (1 byte) */ /* I/T (M)andatory or (O)ptional */
|
||||
#define MSG_CMDCOMPLETE 0x00 /* M/M */
|
||||
#define MSG_EXTENDED 0x01 /* O/O */
|
||||
#define MSG_SAVEDATAPOINTER 0x02 /* O/O */
|
||||
#define MSG_RESTOREPOINTERS 0x03 /* O/O */
|
||||
#define MSG_DISCONNECT 0x04 /* O/O */
|
||||
#define MSG_INITIATOR_DET_ERR 0x05 /* M/M */
|
||||
#define MSG_ABORT 0x06 /* O/M */
|
||||
#define MSG_MESSAGE_REJECT 0x07 /* M/M */
|
||||
#define MSG_NOOP 0x08 /* M/M */
|
||||
#define MSG_PARITY_ERROR 0x09 /* M/M */
|
||||
#define MSG_LINK_CMD_COMPLETE 0x0a /* O/O */
|
||||
#define MSG_LINK_CMD_COMPLETEF 0x0b /* O/O */
|
||||
#define MSG_BUS_DEV_RESET 0x0c /* O/M */
|
||||
#define MSG_ABORT_TAG 0x0d /* O/O */
|
||||
#define MSG_CLEAR_QUEUE 0x0e /* O/O */
|
||||
#define MSG_INIT_RECOVERY 0x0f /* O/O */
|
||||
#define MSG_REL_RECOVERY 0x10 /* O/O */
|
||||
#define MSG_TERM_IO_PROC 0x11 /* O/O */
|
||||
|
||||
/* Messages (2 byte) */
|
||||
#define MSG_SIMPLE_Q_TAG 0x20 /* O/O */
|
||||
#define MSG_HEAD_OF_Q_TAG 0x21 /* O/O */
|
||||
#define MSG_ORDERED_Q_TAG 0x22 /* O/O */
|
||||
#define MSG_IGN_WIDE_RESIDUE 0x23 /* O/O */
|
||||
|
||||
/* Identify message */ /* M/M */
|
||||
#define MSG_IDENTIFYFLAG 0x80
|
||||
#define MSG_IDENTIFY_DISCFLAG 0x40
|
||||
#define MSG_IDENTIFY(lun, disc) (((disc) ? 0xc0 : MSG_IDENTIFYFLAG) | (lun))
|
||||
#define MSG_ISIDENTIFY(m) ((m) & MSG_IDENTIFYFLAG)
|
||||
#define MSG_IDENTIFY_LUNMASK 0x01F
|
||||
|
||||
/* Extended messages (opcode and length) */
|
||||
#define MSG_EXT_SDTR 0x01
|
||||
#define MSG_EXT_SDTR_LEN 0x03
|
||||
|
||||
#define MSG_EXT_WDTR 0x03
|
||||
#define MSG_EXT_WDTR_LEN 0x02
|
||||
#define MSG_EXT_WDTR_BUS_8_BIT 0x00
|
||||
#define MSG_EXT_WDTR_BUS_16_BIT 0x01
|
||||
#define MSG_EXT_WDTR_BUS_32_BIT 0x02
|
787
sys/cam/scsi/scsi_pass.c
Normal file
787
sys/cam/scsi/scsi_pass.c
Normal file
@ -0,0 +1,787 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 1998 Justin T. Gibbs.
|
||||
* Copyright (c) 1997, 1998 Kenneth D. Merry.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification, immediately at the beginning of the file.
|
||||
* 2. 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/dkbad.h>
|
||||
#include <sys/disklabel.h>
|
||||
#include <sys/diskslice.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/cdio.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/devicestat.h>
|
||||
|
||||
#include <cam/cam.h>
|
||||
#include <cam/cam_ccb.h>
|
||||
#include <cam/cam_extend.h>
|
||||
#include <cam/cam_periph.h>
|
||||
#include <cam/cam_xpt_periph.h>
|
||||
#include <cam/cam_debug.h>
|
||||
|
||||
#include <cam/scsi/scsi_all.h>
|
||||
#include <cam/scsi/scsi_message.h>
|
||||
#include <cam/scsi/scsi_da.h>
|
||||
#include <cam/scsi/scsi_pass.h>
|
||||
|
||||
typedef enum {
|
||||
PASS_FLAG_OPEN = 0x01,
|
||||
PASS_FLAG_LOCKED = 0x02,
|
||||
PASS_FLAG_INVALID = 0x04
|
||||
} pass_flags;
|
||||
|
||||
typedef enum {
|
||||
PASS_STATE_NORMAL
|
||||
} pass_state;
|
||||
|
||||
typedef enum {
|
||||
PASS_CCB_BUFFER_IO,
|
||||
PASS_CCB_WAITING
|
||||
} pass_ccb_types;
|
||||
|
||||
#define ccb_type ppriv_field0
|
||||
#define ccb_bp ppriv_ptr1
|
||||
|
||||
struct pass_softc {
|
||||
pass_state state;
|
||||
pass_flags flags;
|
||||
u_int8_t pd_type;
|
||||
struct buf_queue_head buf_queue;
|
||||
union ccb saved_ccb;
|
||||
struct devstat device_stats;
|
||||
#ifdef DEVFS
|
||||
void *pass_devfs_token;
|
||||
void *ctl_devfs_token;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(x,y) ((x<y) ? x : y)
|
||||
#endif
|
||||
|
||||
#define PASS_CDEV_MAJOR 31
|
||||
|
||||
static d_open_t passopen;
|
||||
static d_read_t passread;
|
||||
static d_write_t passwrite;
|
||||
static d_close_t passclose;
|
||||
static d_ioctl_t passioctl;
|
||||
static d_strategy_t passstrategy;
|
||||
|
||||
static periph_init_t passinit;
|
||||
static periph_ctor_t passregister;
|
||||
static periph_dtor_t passcleanup;
|
||||
static periph_start_t passstart;
|
||||
static void passasync(void *callback_arg, u_int32_t code,
|
||||
struct cam_path *path, void *arg);
|
||||
static void passdone(struct cam_periph *periph,
|
||||
union ccb *done_ccb);
|
||||
static int passerror(union ccb *ccb, u_int32_t cam_flags,
|
||||
u_int32_t sense_flags);
|
||||
static int passsendccb(struct cam_periph *periph, union ccb *ccb,
|
||||
union ccb *inccb);
|
||||
|
||||
static struct periph_driver passdriver =
|
||||
{
|
||||
passinit, "pass",
|
||||
TAILQ_HEAD_INITIALIZER(passdriver.units), /* generation */ 0
|
||||
};
|
||||
|
||||
DATA_SET(periphdriver_set, passdriver);
|
||||
|
||||
static struct cdevsw pass_cdevsw =
|
||||
{
|
||||
/*d_open*/ passopen,
|
||||
/*d_close*/ passclose,
|
||||
/*d_read*/ passread,
|
||||
/*d_write*/ passwrite,
|
||||
/*d_ioctl*/ passioctl,
|
||||
/*d_stop*/ nostop,
|
||||
/*d_reset*/ noreset,
|
||||
/*d_devtotty*/ nodevtotty,
|
||||
/*d_poll*/ seltrue,
|
||||
/*d_mmap*/ nommap,
|
||||
/*d_strategy*/ passstrategy,
|
||||
/*d_name*/ "pass",
|
||||
/*d_spare*/ NULL,
|
||||
/*d_maj*/ -1,
|
||||
/*d_dump*/ nodump,
|
||||
/*d_psize*/ nopsize,
|
||||
/*d_flags*/ 0,
|
||||
/*d_maxio*/ 0,
|
||||
/*b_maj*/ -1
|
||||
};
|
||||
|
||||
static struct extend_array *passperiphs;
|
||||
|
||||
static void
|
||||
passinit(void)
|
||||
{
|
||||
cam_status status;
|
||||
struct cam_path *path;
|
||||
|
||||
/*
|
||||
* Create our extend array for storing the devices we attach to.
|
||||
*/
|
||||
passperiphs = cam_extend_new();
|
||||
if (passperiphs == NULL) {
|
||||
printf("passm: Failed to alloc extend array!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Install a global async callback. This callback will
|
||||
* receive async callbacks like "new device found".
|
||||
*/
|
||||
status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,
|
||||
CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
|
||||
|
||||
if (status == CAM_REQ_CMP) {
|
||||
struct ccb_setasync csa;
|
||||
|
||||
xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
|
||||
csa.ccb_h.func_code = XPT_SASYNC_CB;
|
||||
csa.event_enable = AC_FOUND_DEVICE;
|
||||
csa.callback = passasync;
|
||||
csa.callback_arg = NULL;
|
||||
xpt_action((union ccb *)&csa);
|
||||
status = csa.ccb_h.status;
|
||||
xpt_free_path(path);
|
||||
}
|
||||
|
||||
if (status != CAM_REQ_CMP) {
|
||||
printf("pass: Failed to attach master async callback "
|
||||
"due to status 0x%x!\n", status);
|
||||
} else {
|
||||
dev_t dev;
|
||||
|
||||
/* If we were successfull, register our devsw */
|
||||
dev = makedev(PASS_CDEV_MAJOR, 0);
|
||||
cdevsw_add(&dev, &pass_cdevsw, NULL);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
passcleanup(struct cam_periph *periph)
|
||||
{
|
||||
cam_extend_release(passperiphs, periph->unit_number);
|
||||
|
||||
if (bootverbose) {
|
||||
xpt_print_path(periph->path);
|
||||
printf("removing device entry\n");
|
||||
}
|
||||
free(periph->softc, M_DEVBUF);
|
||||
}
|
||||
|
||||
static void
|
||||
passasync(void *callback_arg, u_int32_t code,
|
||||
struct cam_path *path, void *arg)
|
||||
{
|
||||
struct cam_periph *periph;
|
||||
|
||||
periph = (struct cam_periph *)callback_arg;
|
||||
|
||||
switch (code) {
|
||||
case AC_FOUND_DEVICE:
|
||||
{
|
||||
struct ccb_getdev *cgd;
|
||||
cam_status status;
|
||||
|
||||
cgd = (struct ccb_getdev *)arg;
|
||||
|
||||
/*
|
||||
* Allocate a peripheral instance for
|
||||
* this device and start the probe
|
||||
* process.
|
||||
*/
|
||||
status = cam_periph_alloc(passregister, passcleanup, passstart,
|
||||
"pass", CAM_PERIPH_BIO,
|
||||
cgd->ccb_h.path, passasync,
|
||||
AC_FOUND_DEVICE, cgd);
|
||||
|
||||
if (status != CAM_REQ_CMP
|
||||
&& status != CAM_REQ_INPROG)
|
||||
printf("passasync: Unable to attach new device "
|
||||
"due to status 0x%x\n", status);
|
||||
|
||||
break;
|
||||
}
|
||||
case AC_LOST_DEVICE:
|
||||
{
|
||||
int s;
|
||||
struct pass_softc *softc;
|
||||
struct buf *q_bp;
|
||||
struct ccb_setasync csa;
|
||||
|
||||
softc = (struct pass_softc *)periph->softc;
|
||||
|
||||
/*
|
||||
* Insure that no other async callbacks that
|
||||
* might affect this peripheral can come through.
|
||||
*/
|
||||
s = splcam();
|
||||
|
||||
/*
|
||||
* De-register any async callbacks.
|
||||
*/
|
||||
xpt_setup_ccb(&csa.ccb_h, periph->path,
|
||||
/* priority */ 5);
|
||||
csa.ccb_h.func_code = XPT_SASYNC_CB;
|
||||
csa.event_enable = 0;
|
||||
csa.callback = passasync;
|
||||
csa.callback_arg = periph;
|
||||
xpt_action((union ccb *)&csa);
|
||||
|
||||
softc->flags |= PASS_FLAG_INVALID;
|
||||
|
||||
/*
|
||||
* Return all queued I/O with ENXIO.
|
||||
* XXX Handle any transactions queued to the card
|
||||
* with XPT_ABORT_CCB.
|
||||
*/
|
||||
while ((q_bp = bufq_first(&softc->buf_queue)) != NULL){
|
||||
bufq_remove(&softc->buf_queue, q_bp);
|
||||
q_bp->b_resid = q_bp->b_bcount;
|
||||
q_bp->b_error = ENXIO;
|
||||
q_bp->b_flags |= B_ERROR;
|
||||
biodone(q_bp);
|
||||
}
|
||||
devstat_remove_entry(&softc->device_stats);
|
||||
|
||||
if (bootverbose) {
|
||||
xpt_print_path(periph->path);
|
||||
printf("lost device\n");
|
||||
}
|
||||
|
||||
splx(s);
|
||||
|
||||
cam_periph_invalidate(periph);
|
||||
break;
|
||||
}
|
||||
case AC_TRANSFER_NEG:
|
||||
case AC_SENT_BDR:
|
||||
case AC_SCSI_AEN:
|
||||
case AC_UNSOL_RESEL:
|
||||
case AC_BUS_RESET:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static cam_status
|
||||
passregister(struct cam_periph *periph, void *arg)
|
||||
{
|
||||
int s;
|
||||
struct pass_softc *softc;
|
||||
struct ccb_setasync csa;
|
||||
struct ccb_getdev *cgd;
|
||||
|
||||
cgd = (struct ccb_getdev *)arg;
|
||||
if (periph == NULL) {
|
||||
printf("passregister: periph was NULL!!\n");
|
||||
return(CAM_REQ_CMP_ERR);
|
||||
}
|
||||
|
||||
if (cgd == NULL) {
|
||||
printf("passregister: no getdev CCB, can't register device\n");
|
||||
return(CAM_REQ_CMP_ERR);
|
||||
}
|
||||
|
||||
softc = (struct pass_softc *)malloc(sizeof(*softc),
|
||||
M_DEVBUF, M_NOWAIT);
|
||||
|
||||
if (softc == NULL) {
|
||||
printf("passregister: Unable to probe new device. "
|
||||
"Unable to allocate softc\n");
|
||||
return(CAM_REQ_CMP_ERR);
|
||||
}
|
||||
|
||||
bzero(softc, sizeof(*softc));
|
||||
softc->state = PASS_STATE_NORMAL;
|
||||
softc->pd_type = cgd->pd_type;
|
||||
bufq_init(&softc->buf_queue);
|
||||
|
||||
periph->softc = softc;
|
||||
|
||||
cam_extend_set(passperiphs, periph->unit_number, periph);
|
||||
/*
|
||||
* We pass in 0 for a blocksize, since we don't
|
||||
* know what the blocksize of this device is, if
|
||||
* it even has a blocksize.
|
||||
*/
|
||||
devstat_add_entry(&softc->device_stats, "pass", periph->unit_number,
|
||||
0, DEVSTAT_NO_BLOCKSIZE | DEVSTAT_NO_ORDERED_TAGS,
|
||||
cgd->pd_type |
|
||||
DEVSTAT_TYPE_IF_SCSI |
|
||||
DEVSTAT_TYPE_PASS);
|
||||
/*
|
||||
* Add an async callback so that we get
|
||||
* notified if this device goes away.
|
||||
*/
|
||||
xpt_setup_ccb(&csa.ccb_h, periph->path, /* priority */ 5);
|
||||
csa.ccb_h.func_code = XPT_SASYNC_CB;
|
||||
csa.event_enable = AC_LOST_DEVICE;
|
||||
csa.callback = passasync;
|
||||
csa.callback_arg = periph;
|
||||
xpt_action((union ccb *)&csa);
|
||||
|
||||
if (bootverbose)
|
||||
xpt_announce_periph(periph, NULL);
|
||||
|
||||
return(CAM_REQ_CMP);
|
||||
}
|
||||
|
||||
static int
|
||||
passopen(dev_t dev, int flags, int fmt, struct proc *p)
|
||||
{
|
||||
struct cam_periph *periph;
|
||||
struct pass_softc *softc;
|
||||
int unit, error;
|
||||
|
||||
error = 0; /* default to no error */
|
||||
|
||||
/* unit = dkunit(dev); */
|
||||
/* XXX KDM fix this */
|
||||
unit = minor(dev) & 0xff;
|
||||
|
||||
periph = cam_extend_get(passperiphs, unit);
|
||||
|
||||
if (periph == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
softc = (struct pass_softc *)periph->softc;
|
||||
|
||||
if (softc->flags & PASS_FLAG_INVALID)
|
||||
return(ENXIO);
|
||||
|
||||
/*
|
||||
* We don't allow nonblocking access.
|
||||
*/
|
||||
if ((flags & O_NONBLOCK) != 0) {
|
||||
printf("%s%d: can't do nonblocking accesss\n",
|
||||
periph->periph_name,
|
||||
periph->unit_number);
|
||||
return(ENODEV);
|
||||
}
|
||||
|
||||
if ((error = cam_periph_lock(periph, PRIBIO | PCATCH)) != 0)
|
||||
return (error);
|
||||
|
||||
if ((softc->flags & PASS_FLAG_OPEN) == 0) {
|
||||
if (cam_periph_acquire(periph) != CAM_REQ_CMP)
|
||||
return(ENXIO);
|
||||
softc->flags |= PASS_FLAG_OPEN;
|
||||
}
|
||||
|
||||
cam_periph_unlock(periph);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
passclose(dev_t dev, int flag, int fmt, struct proc *p)
|
||||
{
|
||||
struct cam_periph *periph;
|
||||
struct pass_softc *softc;
|
||||
int unit, error;
|
||||
|
||||
/* unit = dkunit(dev); */
|
||||
/* XXX KDM fix this */
|
||||
unit = minor(dev) & 0xff;
|
||||
|
||||
periph = cam_extend_get(passperiphs, unit);
|
||||
if (periph == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
softc = (struct pass_softc *)periph->softc;
|
||||
|
||||
if ((error = cam_periph_lock(periph, PRIBIO)) != 0)
|
||||
return (error);
|
||||
|
||||
softc->flags &= ~PASS_FLAG_OPEN;
|
||||
|
||||
cam_periph_unlock(periph);
|
||||
cam_periph_release(periph);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
passread(dev_t dev, struct uio *uio, int ioflag)
|
||||
{
|
||||
return(physio(passstrategy, NULL, dev, 1, minphys, uio));
|
||||
}
|
||||
|
||||
static int
|
||||
passwrite(dev_t dev, struct uio *uio, int ioflag)
|
||||
{
|
||||
return(physio(passstrategy, NULL, dev, 0, minphys, uio));
|
||||
}
|
||||
|
||||
/*
|
||||
* Actually translate the requested transfer into one the physical driver
|
||||
* can understand. The transfer is described by a buf and will include
|
||||
* only one physical transfer.
|
||||
*/
|
||||
static void
|
||||
passstrategy(struct buf *bp)
|
||||
{
|
||||
struct cam_periph *periph;
|
||||
struct pass_softc *softc;
|
||||
u_int unit;
|
||||
int s;
|
||||
|
||||
/*
|
||||
* The read/write interface for the passthrough driver doesn't
|
||||
* really work right now. So, we just pass back EINVAL to tell the
|
||||
* user to go away.
|
||||
*/
|
||||
bp->b_error = EINVAL;
|
||||
goto bad;
|
||||
|
||||
/* unit = dkunit(bp->b_dev); */
|
||||
/* XXX KDM fix this */
|
||||
unit = minor(bp->b_dev) & 0xff;
|
||||
|
||||
periph = cam_extend_get(passperiphs, unit);
|
||||
if (periph == NULL) {
|
||||
bp->b_error = ENXIO;
|
||||
goto bad;
|
||||
}
|
||||
softc = (struct pass_softc *)periph->softc;
|
||||
|
||||
/*
|
||||
* Odd number of bytes or negative offset
|
||||
*/
|
||||
/* valid request? */
|
||||
if (bp->b_blkno < 0) {
|
||||
bp->b_error = EINVAL;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mask interrupts so that the pack cannot be invalidated until
|
||||
* after we are in the queue. Otherwise, we might not properly
|
||||
* clean up one of the buffers.
|
||||
*/
|
||||
s = splbio();
|
||||
|
||||
bufq_insert_tail(&softc->buf_queue, bp);
|
||||
|
||||
splx(s);
|
||||
|
||||
/*
|
||||
* Schedule ourselves for performing the work.
|
||||
*/
|
||||
xpt_schedule(periph, /* XXX priority */1);
|
||||
|
||||
return;
|
||||
bad:
|
||||
bp->b_flags |= B_ERROR;
|
||||
|
||||
/*
|
||||
* Correctly set the buf to indicate a completed xfer
|
||||
*/
|
||||
bp->b_resid = bp->b_bcount;
|
||||
biodone(bp);
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
passstart(struct cam_periph *periph, union ccb *start_ccb)
|
||||
{
|
||||
struct pass_softc *softc;
|
||||
int s;
|
||||
|
||||
softc = (struct pass_softc *)periph->softc;
|
||||
|
||||
switch (softc->state) {
|
||||
case PASS_STATE_NORMAL:
|
||||
{
|
||||
struct buf *bp;
|
||||
|
||||
s = splbio();
|
||||
bp = bufq_first(&softc->buf_queue);
|
||||
if (periph->immediate_priority <= periph->pinfo.priority) {
|
||||
start_ccb->ccb_h.ccb_type = PASS_CCB_WAITING;
|
||||
SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
|
||||
periph_links.sle);
|
||||
periph->immediate_priority = CAM_PRIORITY_NONE;
|
||||
splx(s);
|
||||
wakeup(&periph->ccb_list);
|
||||
} else if (bp == NULL) {
|
||||
splx(s);
|
||||
xpt_release_ccb(start_ccb);
|
||||
} else {
|
||||
|
||||
bufq_remove(&softc->buf_queue, bp);
|
||||
|
||||
devstat_start_transaction(&softc->device_stats);
|
||||
|
||||
/*
|
||||
* XXX JGibbs -
|
||||
* Interpret the contents of the bp as a CCB
|
||||
* and pass it to a routine shared by our ioctl
|
||||
* code and passtart.
|
||||
* For now, just biodone it with EIO so we don't
|
||||
* hang.
|
||||
*/
|
||||
bp->b_error = EIO;
|
||||
bp->b_flags |= B_ERROR;
|
||||
bp->b_resid = bp->b_bcount;
|
||||
biodone(bp);
|
||||
bp = bufq_first(&softc->buf_queue);
|
||||
splx(s);
|
||||
|
||||
xpt_action(start_ccb);
|
||||
|
||||
}
|
||||
if (bp != NULL) {
|
||||
/* Have more work to do, so ensure we stay scheduled */
|
||||
xpt_schedule(periph, /* XXX priority */1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
static void
|
||||
passdone(struct cam_periph *periph, union ccb *done_ccb)
|
||||
{
|
||||
struct pass_softc *softc;
|
||||
struct ccb_scsiio *csio;
|
||||
|
||||
softc = (struct pass_softc *)periph->softc;
|
||||
csio = &done_ccb->csio;
|
||||
switch (csio->ccb_h.ccb_type) {
|
||||
case PASS_CCB_BUFFER_IO:
|
||||
{
|
||||
struct buf *bp;
|
||||
cam_status status;
|
||||
u_int8_t scsi_status;
|
||||
devstat_trans_flags ds_flags;
|
||||
|
||||
status = done_ccb->ccb_h.status;
|
||||
scsi_status = done_ccb->csio.scsi_status;
|
||||
bp = (struct buf *)done_ccb->ccb_h.ccb_bp;
|
||||
/* XXX handle errors */
|
||||
if (!(((status & CAM_STATUS_MASK) == CAM_REQ_CMP)
|
||||
&& (scsi_status == SCSI_STATUS_OK))) {
|
||||
int error;
|
||||
|
||||
if ((error = passerror(done_ccb, 0, 0)) == ERESTART) {
|
||||
/*
|
||||
* A retry was scheuled, so
|
||||
* just return.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX unfreeze the queue after we complete
|
||||
* the abort process
|
||||
*/
|
||||
bp->b_error = error;
|
||||
bp->b_flags |= B_ERROR;
|
||||
}
|
||||
|
||||
if ((done_ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
|
||||
ds_flags = DEVSTAT_READ;
|
||||
else if ((done_ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
|
||||
ds_flags = DEVSTAT_WRITE;
|
||||
else
|
||||
ds_flags = DEVSTAT_NO_DATA;
|
||||
|
||||
devstat_end_transaction(&softc->device_stats, bp->b_bcount,
|
||||
done_ccb->csio.tag_action & 0xf,
|
||||
ds_flags);
|
||||
|
||||
biodone(bp);
|
||||
break;
|
||||
}
|
||||
case PASS_CCB_WAITING:
|
||||
{
|
||||
/* Caller will release the CCB */
|
||||
wakeup(&done_ccb->ccb_h.cbfcnp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
xpt_release_ccb(done_ccb);
|
||||
}
|
||||
|
||||
static int
|
||||
passioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
|
||||
{
|
||||
struct cam_periph *periph;
|
||||
struct pass_softc *softc;
|
||||
u_int8_t unit;
|
||||
int error;
|
||||
|
||||
|
||||
/* unit = dkunit(dev); */
|
||||
/* XXX KDM fix this */
|
||||
unit = minor(dev) & 0xff;
|
||||
|
||||
periph = cam_extend_get(passperiphs, unit);
|
||||
|
||||
if (periph == NULL)
|
||||
return(ENXIO);
|
||||
|
||||
softc = (struct pass_softc *)periph->softc;
|
||||
|
||||
error = 0;
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
case CAMIOCOMMAND:
|
||||
{
|
||||
union ccb *inccb;
|
||||
union ccb *ccb;
|
||||
|
||||
inccb = (union ccb *)addr;
|
||||
ccb = cam_periph_getccb(periph, inccb->ccb_h.pinfo.priority);
|
||||
|
||||
error = passsendccb(periph, ccb, inccb);
|
||||
|
||||
xpt_release_ccb(ccb);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
error = cam_periph_ioctl(periph, cmd, addr, passerror);
|
||||
break;
|
||||
}
|
||||
|
||||
return(error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generally, "ccb" should be the CCB supplied by the kernel. "inccb"
|
||||
* should be the CCB that is copied in from the user.
|
||||
*/
|
||||
static int
|
||||
passsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb)
|
||||
{
|
||||
struct buf *bp[2];
|
||||
struct pass_softc *softc;
|
||||
struct cam_periph_map_info mapinfo;
|
||||
int error, need_unmap;
|
||||
|
||||
softc = (struct pass_softc *)periph->softc;
|
||||
|
||||
need_unmap = 0;
|
||||
|
||||
/*
|
||||
* There are some fields in the CCB header that need to be
|
||||
* preserved, the rest we get from the user.
|
||||
*/
|
||||
xpt_merge_ccb(ccb, inccb);
|
||||
|
||||
/*
|
||||
* There's no way for the user to have a completion
|
||||
* function, so we put our own completion function in here.
|
||||
*/
|
||||
ccb->ccb_h.cbfcnp = passdone;
|
||||
|
||||
/*
|
||||
* We only attempt to map the user memory into kernel space
|
||||
* if they haven't passed in a physical memory pointer,
|
||||
* and if there is actually an I/O operation to perform.
|
||||
* Right now cam_periph_mapmem() only supports SCSI and device
|
||||
* match CCBs. For the SCSI CCBs, we only pass the CCB in if
|
||||
* there's actually data to map. cam_periph_mapmem() will do the
|
||||
* right thing, even if there isn't data to map, but since CCBs
|
||||
* without data are a reasonably common occurance (e.g. test unit
|
||||
* ready), it will save a few cycles if we check for it here.
|
||||
*/
|
||||
if (((ccb->ccb_h.flags & CAM_DATA_PHYS) == 0)
|
||||
&& (((ccb->ccb_h.func_code == XPT_SCSI_IO)
|
||||
&& ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE))
|
||||
|| (ccb->ccb_h.func_code == XPT_DEV_MATCH))) {
|
||||
|
||||
bzero(&mapinfo, sizeof(mapinfo));
|
||||
|
||||
error = cam_periph_mapmem(ccb, &mapinfo);
|
||||
|
||||
/*
|
||||
* cam_periph_mapmem returned an error, we can't continue.
|
||||
* Return the error to the user.
|
||||
*/
|
||||
if (error)
|
||||
return(error);
|
||||
|
||||
/*
|
||||
* We successfully mapped the memory in, so we need to
|
||||
* unmap it when the transaction is done.
|
||||
*/
|
||||
need_unmap = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the user wants us to perform any error recovery, then honor
|
||||
* that request. Otherwise, it's up to the user to perform any
|
||||
* error recovery.
|
||||
*/
|
||||
error = cam_periph_runccb(ccb,
|
||||
(ccb->ccb_h.flags & CAM_PASS_ERR_RECOVER) ?
|
||||
passerror : NULL,
|
||||
/* cam_flags */ 0,
|
||||
/* sense_flags */SF_RETRY_UA,
|
||||
&softc->device_stats);
|
||||
|
||||
if (need_unmap != 0)
|
||||
cam_periph_unmapmem(ccb, &mapinfo);
|
||||
|
||||
ccb->ccb_h.cbfcnp = NULL;
|
||||
ccb->ccb_h.periph_priv = inccb->ccb_h.periph_priv;
|
||||
bcopy(ccb, inccb, sizeof(union ccb));
|
||||
|
||||
return(error);
|
||||
}
|
||||
|
||||
static int
|
||||
passerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
|
||||
{
|
||||
struct cam_periph *periph;
|
||||
struct pass_softc *softc;
|
||||
|
||||
periph = xpt_path_periph(ccb->ccb_h.path);
|
||||
softc = (struct pass_softc *)periph->softc;
|
||||
|
||||
return(cam_periph_error(ccb, cam_flags, sense_flags,
|
||||
&softc->saved_ccb));
|
||||
}
|
38
sys/cam/scsi/scsi_pass.h
Normal file
38
sys/cam/scsi/scsi_pass.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 1997 Kenneth D. Merry.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef _SCSI_PASS_H
|
||||
#define _SCSI_PASS_H 1
|
||||
|
||||
#include <sys/ioccom.h>
|
||||
|
||||
#include <cam/cam_ccb.h>
|
||||
|
||||
#define CAMIOCOMMAND _IOWR('Q', 2, union ccb)
|
||||
#define CAMGETPASSTHRU _IOWR('Q', 3, union ccb)
|
||||
|
||||
#endif
|
723
sys/cam/scsi/scsi_pt.c
Normal file
723
sys/cam/scsi/scsi_pt.c
Normal file
@ -0,0 +1,723 @@
|
||||
/*
|
||||
* Implementation of SCSI Processor Target Peripheral driver for CAM.
|
||||
*
|
||||
* Copyright (c) 1998 Justin T. Gibbs.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification, immediately at the beginning of the file.
|
||||
* 2. 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/devicestat.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/conf.h>
|
||||
|
||||
#include <cam/cam.h>
|
||||
#include <cam/cam_ccb.h>
|
||||
#include <cam/cam_extend.h>
|
||||
#include <cam/cam_periph.h>
|
||||
#include <cam/cam_xpt_periph.h>
|
||||
#include <cam/cam_debug.h>
|
||||
|
||||
#include <cam/scsi/scsi_all.h>
|
||||
#include <cam/scsi/scsi_message.h>
|
||||
#include <cam/scsi/scsi_pt.h>
|
||||
|
||||
typedef enum {
|
||||
PT_STATE_PROBE,
|
||||
PT_STATE_NORMAL
|
||||
} pt_state;
|
||||
|
||||
typedef enum {
|
||||
PT_FLAG_NONE = 0x00,
|
||||
PT_FLAG_OPEN = 0x01,
|
||||
PT_FLAG_DEVICE_INVALID = 0x02,
|
||||
PT_FLAG_RETRY_UA = 0x04
|
||||
} pt_flags;
|
||||
|
||||
typedef enum {
|
||||
PT_CCB_BUFFER_IO = 0x01,
|
||||
PT_CCB_WAITING = 0x02,
|
||||
PT_CCB_RETRY_UA = 0x04,
|
||||
PT_CCB_BUFFER_IO_UA = PT_CCB_BUFFER_IO|PT_CCB_RETRY_UA
|
||||
} pt_ccb_state;
|
||||
|
||||
/* Offsets into our private area for storing information */
|
||||
#define ccb_state ppriv_field0
|
||||
#define ccb_bp ppriv_ptr1
|
||||
|
||||
struct pt_softc {
|
||||
struct buf_queue_head buf_queue;
|
||||
struct devstat device_stats;
|
||||
LIST_HEAD(, ccb_hdr) pending_ccbs;
|
||||
pt_state state;
|
||||
pt_flags flags;
|
||||
union ccb saved_ccb;
|
||||
};
|
||||
|
||||
static d_open_t ptopen;
|
||||
static d_read_t ptread;
|
||||
static d_write_t ptwrite;
|
||||
static d_close_t ptclose;
|
||||
static d_strategy_t ptstrategy;
|
||||
static periph_init_t ptinit;
|
||||
static void ptasync(void *callback_arg, u_int32_t code,
|
||||
struct cam_path *path, void *arg);
|
||||
static periph_ctor_t ptctor;
|
||||
static periph_dtor_t ptdtor;
|
||||
static periph_start_t ptstart;
|
||||
static void ptdone(struct cam_periph *periph,
|
||||
union ccb *done_ccb);
|
||||
static int pterror(union ccb *ccb, u_int32_t cam_flags,
|
||||
u_int32_t sense_flags);
|
||||
|
||||
void scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries,
|
||||
void (*cbfcnp)(struct cam_periph *, union ccb *),
|
||||
u_int tag_action, int readop, u_int byte2,
|
||||
u_int32_t xfer_len, u_int8_t *data_ptr,
|
||||
u_int8_t sense_len, u_int32_t timeout);
|
||||
|
||||
static struct periph_driver ptdriver =
|
||||
{
|
||||
ptinit, "pt",
|
||||
TAILQ_HEAD_INITIALIZER(ptdriver.units), /* generation */ 0
|
||||
};
|
||||
|
||||
DATA_SET(periphdriver_set, ptdriver);
|
||||
|
||||
#define PT_CDEV_MAJOR 61
|
||||
|
||||
static struct cdevsw pt_cdevsw =
|
||||
{
|
||||
/*d_open*/ ptopen,
|
||||
/*d_close*/ ptclose,
|
||||
/*d_read*/ ptread,
|
||||
/*d_write*/ ptwrite,
|
||||
/*d_ioctl*/ noioctl,
|
||||
/*d_stop*/ nostop,
|
||||
/*d_reset*/ noreset,
|
||||
/*d_devtotty*/ nodevtotty,
|
||||
/*d_poll*/ seltrue,
|
||||
/*d_mmap*/ nommap,
|
||||
/*d_strategy*/ ptstrategy,
|
||||
/*d_name*/ "pt",
|
||||
/*d_spare*/ NULL,
|
||||
/*d_maj*/ -1,
|
||||
/*d_dump*/ nodump,
|
||||
/*d_psize*/ nopsize,
|
||||
/*d_flags*/ 0,
|
||||
/*d_maxio*/ 0,
|
||||
/*b_maj*/ -1
|
||||
};
|
||||
|
||||
static struct extend_array *ptperiphs;
|
||||
|
||||
static int
|
||||
ptopen(dev_t dev, int flags, int fmt, struct proc *p)
|
||||
{
|
||||
struct cam_periph *periph;
|
||||
struct pt_softc *softc;
|
||||
int unit;
|
||||
int error;
|
||||
|
||||
unit = minor(dev);
|
||||
periph = cam_extend_get(ptperiphs, unit);
|
||||
if (periph == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
softc = (struct pt_softc *)periph->softc;
|
||||
|
||||
CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
|
||||
("ptopen: dev=0x%x (unit %d)\n", dev, unit));
|
||||
|
||||
if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0)
|
||||
return (error); /* error code from tsleep */
|
||||
|
||||
if ((softc->flags & PT_FLAG_OPEN) == 0) {
|
||||
if (cam_periph_acquire(periph) != CAM_REQ_CMP)
|
||||
error = ENXIO;
|
||||
else
|
||||
softc->flags |= PT_FLAG_OPEN;
|
||||
} else
|
||||
error = EBUSY;
|
||||
|
||||
cam_periph_unlock(periph);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
ptclose(dev_t dev, int flag, int fmt, struct proc *p)
|
||||
{
|
||||
struct cam_periph *periph;
|
||||
struct pt_softc *softc;
|
||||
union ccb *ccb;
|
||||
int unit;
|
||||
int error;
|
||||
|
||||
unit = minor(dev);
|
||||
periph = cam_extend_get(ptperiphs, unit);
|
||||
if (periph == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
softc = (struct pt_softc *)periph->softc;
|
||||
|
||||
if ((error = cam_periph_lock(periph, PRIBIO)) != 0)
|
||||
return (error); /* error code from tsleep */
|
||||
|
||||
softc->flags &= ~PT_FLAG_OPEN;
|
||||
cam_periph_unlock(periph);
|
||||
cam_periph_release(periph);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ptread(dev_t dev, struct uio *uio, int ioflag)
|
||||
{
|
||||
return(physio(ptstrategy, NULL, dev, 1, minphys, uio));
|
||||
}
|
||||
|
||||
static int
|
||||
ptwrite(dev_t dev, struct uio *uio, int ioflag)
|
||||
{
|
||||
return(physio(ptstrategy, NULL, dev, 0, minphys, uio));
|
||||
}
|
||||
|
||||
/*
|
||||
* Actually translate the requested transfer into one the physical driver
|
||||
* can understand. The transfer is described by a buf and will include
|
||||
* only one physical transfer.
|
||||
*/
|
||||
static void
|
||||
ptstrategy(struct buf *bp)
|
||||
{
|
||||
struct cam_periph *periph;
|
||||
struct pt_softc *softc;
|
||||
u_int unit;
|
||||
int s;
|
||||
|
||||
unit = minor(bp->b_dev);
|
||||
periph = cam_extend_get(ptperiphs, unit);
|
||||
if (periph == NULL) {
|
||||
bp->b_error = ENXIO;
|
||||
goto bad;
|
||||
}
|
||||
softc = (struct pt_softc *)periph->softc;
|
||||
|
||||
/*
|
||||
* Mask interrupts so that the pack cannot be invalidated until
|
||||
* after we are in the queue. Otherwise, we might not properly
|
||||
* clean up one of the buffers.
|
||||
*/
|
||||
s = splbio();
|
||||
|
||||
/*
|
||||
* If the device has been made invalid, error out
|
||||
*/
|
||||
if ((softc->flags & PT_FLAG_DEVICE_INVALID)) {
|
||||
splx(s);
|
||||
bp->b_error = ENXIO;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* Place it in the queue of disk activities for this disk
|
||||
*/
|
||||
bufq_insert_tail(&softc->buf_queue, bp);
|
||||
|
||||
splx(s);
|
||||
|
||||
/*
|
||||
* Schedule ourselves for performing the work.
|
||||
*/
|
||||
xpt_schedule(periph, /* XXX priority */1);
|
||||
|
||||
return;
|
||||
bad:
|
||||
bp->b_flags |= B_ERROR;
|
||||
|
||||
/*
|
||||
* Correctly set the buf to indicate a completed xfer
|
||||
*/
|
||||
bp->b_resid = bp->b_bcount;
|
||||
biodone(bp);
|
||||
}
|
||||
|
||||
static void
|
||||
ptinit(void)
|
||||
{
|
||||
cam_status status;
|
||||
struct cam_path *path;
|
||||
|
||||
/*
|
||||
* Create our extend array for storing the devices we attach to.
|
||||
*/
|
||||
ptperiphs = cam_extend_new();
|
||||
if (ptperiphs == NULL) {
|
||||
printf("pt: Failed to alloc extend array!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Install a global async callback. This callback will
|
||||
* receive async callbacks like "new device found".
|
||||
*/
|
||||
status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,
|
||||
CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
|
||||
|
||||
if (status == CAM_REQ_CMP) {
|
||||
struct ccb_setasync csa;
|
||||
|
||||
xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
|
||||
csa.ccb_h.func_code = XPT_SASYNC_CB;
|
||||
csa.event_enable = AC_FOUND_DEVICE;
|
||||
csa.callback = ptasync;
|
||||
csa.callback_arg = NULL;
|
||||
xpt_action((union ccb *)&csa);
|
||||
status = csa.ccb_h.status;
|
||||
xpt_free_path(path);
|
||||
}
|
||||
|
||||
if (status != CAM_REQ_CMP) {
|
||||
printf("pt: Failed to attach master async callback "
|
||||
"due to status 0x%x!\n", status);
|
||||
} else {
|
||||
/* If we were successfull, register our devsw */
|
||||
dev_t dev;
|
||||
|
||||
dev = makedev(PT_CDEV_MAJOR, 0);
|
||||
cdevsw_add(&dev,&pt_cdevsw, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static cam_status
|
||||
ptctor(struct cam_periph *periph, void *arg)
|
||||
{
|
||||
int s;
|
||||
struct pt_softc *softc;
|
||||
struct ccb_setasync csa;
|
||||
struct ccb_getdev *cgd;
|
||||
|
||||
cgd = (struct ccb_getdev *)arg;
|
||||
if (periph == NULL) {
|
||||
printf("ptregister: periph was NULL!!\n");
|
||||
return(CAM_REQ_CMP_ERR);
|
||||
}
|
||||
|
||||
if (cgd == NULL) {
|
||||
printf("ptregister: no getdev CCB, can't register device\n");
|
||||
return(CAM_REQ_CMP_ERR);
|
||||
}
|
||||
|
||||
softc = (struct pt_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT);
|
||||
|
||||
if (softc == NULL) {
|
||||
printf("daregister: Unable to probe new device. "
|
||||
"Unable to allocate softc\n");
|
||||
return(CAM_REQ_CMP_ERR);
|
||||
}
|
||||
|
||||
bzero(softc, sizeof(*softc));
|
||||
LIST_INIT(&softc->pending_ccbs);
|
||||
softc->state = PT_STATE_NORMAL;
|
||||
bufq_init(&softc->buf_queue);
|
||||
|
||||
periph->softc = softc;
|
||||
|
||||
cam_extend_set(ptperiphs, periph->unit_number, periph);
|
||||
|
||||
/*
|
||||
* The DA driver supports a blocksize, but
|
||||
* we don't know the blocksize until we do
|
||||
* a read capacity. So, set a flag to
|
||||
* indicate that the blocksize is
|
||||
* unavailable right now. We'll clear the
|
||||
* flag as soon as we've done a read capacity.
|
||||
*/
|
||||
devstat_add_entry(&softc->device_stats, "pt",
|
||||
periph->unit_number, 0,
|
||||
DEVSTAT_NO_BLOCKSIZE,
|
||||
cgd->pd_type | DEVSTAT_TYPE_IF_SCSI);
|
||||
|
||||
/*
|
||||
* Add async callbacks for bus reset and
|
||||
* bus device reset calls. I don't bother
|
||||
* checking if this fails as, in most cases,
|
||||
* the system will function just fine without
|
||||
* them and the only alternative would be to
|
||||
* not attach the device on failure.
|
||||
*/
|
||||
xpt_setup_ccb(&csa.ccb_h, periph->path, /*priority*/5);
|
||||
csa.ccb_h.func_code = XPT_SASYNC_CB;
|
||||
csa.event_enable = AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE;
|
||||
csa.callback = ptasync;
|
||||
csa.callback_arg = periph;
|
||||
xpt_action((union ccb *)&csa);
|
||||
|
||||
/* Tell the user we've attached to the device */
|
||||
xpt_announce_periph(periph, NULL);
|
||||
|
||||
return(CAM_REQ_CMP);
|
||||
}
|
||||
|
||||
static void
|
||||
ptdtor(struct cam_periph *periph)
|
||||
{
|
||||
cam_extend_release(ptperiphs, periph->unit_number);
|
||||
xpt_print_path(periph->path);
|
||||
printf("removing device entry\n");
|
||||
free(periph->softc, M_DEVBUF);
|
||||
}
|
||||
|
||||
static void
|
||||
ptasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
|
||||
{
|
||||
struct cam_periph *periph;
|
||||
|
||||
periph = (struct cam_periph *)callback_arg;
|
||||
switch (code) {
|
||||
case AC_FOUND_DEVICE:
|
||||
{
|
||||
struct ccb_getdev *cgd;
|
||||
cam_status status;
|
||||
|
||||
cgd = (struct ccb_getdev *)arg;
|
||||
|
||||
if (cgd->pd_type != T_PROCESSOR)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Allocate a peripheral instance for
|
||||
* this device and start the probe
|
||||
* process.
|
||||
*/
|
||||
status = cam_periph_alloc(ptctor, ptdtor, ptstart,
|
||||
"pt", CAM_PERIPH_BIO, cgd->ccb_h.path,
|
||||
ptasync, AC_FOUND_DEVICE, cgd);
|
||||
|
||||
if (status != CAM_REQ_CMP
|
||||
&& status != CAM_REQ_INPROG)
|
||||
printf("ptasync: Unable to attach to new device "
|
||||
"due to status 0x%x\n", status);
|
||||
break;
|
||||
}
|
||||
case AC_LOST_DEVICE:
|
||||
{
|
||||
int s;
|
||||
struct pt_softc *softc;
|
||||
struct buf *q_bp;
|
||||
struct ccb_setasync csa;
|
||||
|
||||
softc = (struct pt_softc *)periph->softc;
|
||||
|
||||
/*
|
||||
* Insure that no other async callbacks that
|
||||
* might affect this peripheral can come through.
|
||||
*/
|
||||
s = splcam();
|
||||
|
||||
/*
|
||||
* De-register any async callbacks.
|
||||
*/
|
||||
xpt_setup_ccb(&csa.ccb_h, periph->path,
|
||||
/* priority */ 5);
|
||||
csa.ccb_h.func_code = XPT_SASYNC_CB;
|
||||
csa.event_enable = 0;
|
||||
csa.callback = ptasync;
|
||||
csa.callback_arg = periph;
|
||||
xpt_action((union ccb *)&csa);
|
||||
|
||||
softc->flags |= PT_FLAG_DEVICE_INVALID;
|
||||
|
||||
/*
|
||||
* Return all queued I/O with ENXIO.
|
||||
* XXX Handle any transactions queued to the card
|
||||
* with XPT_ABORT_CCB.
|
||||
*/
|
||||
while ((q_bp = bufq_first(&softc->buf_queue)) != NULL){
|
||||
bufq_remove(&softc->buf_queue, q_bp);
|
||||
q_bp->b_resid = q_bp->b_bcount;
|
||||
q_bp->b_error = ENXIO;
|
||||
q_bp->b_flags |= B_ERROR;
|
||||
biodone(q_bp);
|
||||
}
|
||||
devstat_remove_entry(&softc->device_stats);
|
||||
|
||||
xpt_print_path(periph->path);
|
||||
printf("lost device\n");
|
||||
|
||||
splx(s);
|
||||
|
||||
cam_periph_invalidate(periph);
|
||||
break;
|
||||
}
|
||||
case AC_SENT_BDR:
|
||||
case AC_BUS_RESET:
|
||||
{
|
||||
struct pt_softc *softc;
|
||||
struct ccb_hdr *ccbh;
|
||||
int s;
|
||||
|
||||
softc = (struct pt_softc *)periph->softc;
|
||||
s = splsoftcam();
|
||||
/*
|
||||
* Don't fail on the expected unit attention
|
||||
* that will occur.
|
||||
*/
|
||||
softc->flags |= PT_FLAG_RETRY_UA;
|
||||
for (ccbh = LIST_FIRST(&softc->pending_ccbs);
|
||||
ccbh != NULL; ccbh = LIST_NEXT(ccbh, periph_links.le))
|
||||
ccbh->ccb_state |= PT_CCB_RETRY_UA;
|
||||
splx(s);
|
||||
break;
|
||||
}
|
||||
case AC_TRANSFER_NEG:
|
||||
case AC_SCSI_AEN:
|
||||
case AC_UNSOL_RESEL:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ptstart(struct cam_periph *periph, union ccb *start_ccb)
|
||||
{
|
||||
struct pt_softc *softc;
|
||||
struct buf *bp;
|
||||
int s;
|
||||
|
||||
softc = (struct pt_softc *)periph->softc;
|
||||
|
||||
/*
|
||||
* See if there is a buf with work for us to do..
|
||||
*/
|
||||
s = splbio();
|
||||
bp = bufq_first(&softc->buf_queue);
|
||||
if (periph->immediate_priority <= periph->pinfo.priority) {
|
||||
CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE,
|
||||
("queuing for immediate ccb\n"));
|
||||
start_ccb->ccb_h.ccb_state = PT_CCB_WAITING;
|
||||
SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
|
||||
periph_links.sle);
|
||||
periph->immediate_priority = CAM_PRIORITY_NONE;
|
||||
splx(s);
|
||||
wakeup(&periph->ccb_list);
|
||||
} else if (bp == NULL) {
|
||||
splx(s);
|
||||
xpt_release_ccb(start_ccb);
|
||||
} else {
|
||||
int oldspl;
|
||||
|
||||
bufq_remove(&softc->buf_queue, bp);
|
||||
|
||||
devstat_start_transaction(&softc->device_stats);
|
||||
|
||||
scsi_send_receive(&start_ccb->csio,
|
||||
/*retries*/4,
|
||||
ptdone,
|
||||
MSG_SIMPLE_Q_TAG,
|
||||
bp->b_flags & B_READ,
|
||||
/*byte2*/0,
|
||||
bp->b_bcount,
|
||||
bp->b_data,
|
||||
/*sense_len*/SSD_FULL_SIZE,
|
||||
/*timeout*/10000);
|
||||
|
||||
start_ccb->ccb_h.ccb_state = PT_CCB_BUFFER_IO;
|
||||
|
||||
/*
|
||||
* Block out any asyncronous callbacks
|
||||
* while we touch the pending ccb list.
|
||||
*/
|
||||
oldspl = splcam();
|
||||
LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h,
|
||||
periph_links.le);
|
||||
splx(oldspl);
|
||||
|
||||
start_ccb->ccb_h.ccb_bp = bp;
|
||||
bp = bufq_first(&softc->buf_queue);
|
||||
splx(s);
|
||||
|
||||
xpt_action(start_ccb);
|
||||
|
||||
if (bp != NULL) {
|
||||
/* Have more work to do, so ensure we stay scheduled */
|
||||
xpt_schedule(periph, /* XXX priority */1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ptdone(struct cam_periph *periph, union ccb *done_ccb)
|
||||
{
|
||||
struct pt_softc *softc;
|
||||
struct ccb_scsiio *csio;
|
||||
|
||||
softc = (struct pt_softc *)periph->softc;
|
||||
csio = &done_ccb->csio;
|
||||
switch (csio->ccb_h.ccb_state) {
|
||||
case PT_CCB_BUFFER_IO:
|
||||
case PT_CCB_BUFFER_IO_UA:
|
||||
{
|
||||
struct buf *bp;
|
||||
int oldspl;
|
||||
|
||||
bp = (struct buf *)done_ccb->ccb_h.ccb_bp;
|
||||
if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
|
||||
int error;
|
||||
int s;
|
||||
int sf;
|
||||
|
||||
if ((csio->ccb_h.ccb_state & PT_CCB_RETRY_UA) != 0)
|
||||
sf = SF_RETRY_UA;
|
||||
else
|
||||
sf = 0;
|
||||
|
||||
if ((error = pterror(done_ccb, 0, sf)) == ERESTART) {
|
||||
/*
|
||||
* A retry was scheuled, so
|
||||
* just return.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
if (error != 0) {
|
||||
struct buf *q_bp;
|
||||
|
||||
s = splbio();
|
||||
|
||||
if (error == ENXIO) {
|
||||
/*
|
||||
* Catastrophic error. Mark our device
|
||||
* as invalid.
|
||||
*/
|
||||
xpt_print_path(periph->path);
|
||||
printf("Invalidating device\n");
|
||||
softc->flags |= PT_FLAG_DEVICE_INVALID;
|
||||
}
|
||||
|
||||
/*
|
||||
* return all queued I/O with EIO, so that
|
||||
* the client can retry these I/Os in the
|
||||
* proper order should it attempt to recover.
|
||||
*/
|
||||
while ((q_bp = bufq_first(&softc->buf_queue))
|
||||
!= NULL) {
|
||||
bufq_remove(&softc->buf_queue, q_bp);
|
||||
q_bp->b_resid = q_bp->b_bcount;
|
||||
q_bp->b_error = EIO;
|
||||
q_bp->b_flags |= B_ERROR;
|
||||
biodone(q_bp);
|
||||
}
|
||||
splx(s);
|
||||
bp->b_error = error;
|
||||
bp->b_resid = bp->b_bcount;
|
||||
bp->b_flags |= B_ERROR;
|
||||
} else {
|
||||
bp->b_resid = csio->resid;
|
||||
bp->b_error = 0;
|
||||
if (bp->b_resid != 0) {
|
||||
/* Short transfer ??? */
|
||||
bp->b_flags |= B_ERROR;
|
||||
}
|
||||
}
|
||||
if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
|
||||
cam_release_devq(done_ccb->ccb_h.path,
|
||||
/*relsim_flags*/0,
|
||||
/*reduction*/0,
|
||||
/*timeout*/0,
|
||||
/*getcount_only*/0);
|
||||
} else {
|
||||
bp->b_resid = csio->resid;
|
||||
if (bp->b_resid != 0)
|
||||
bp->b_flags |= B_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Block out any asyncronous callbacks
|
||||
* while we touch the pending ccb list.
|
||||
*/
|
||||
oldspl = splcam();
|
||||
LIST_REMOVE(&done_ccb->ccb_h, periph_links.le);
|
||||
splx(oldspl);
|
||||
|
||||
devstat_end_transaction(&softc->device_stats,
|
||||
bp->b_bcount - bp->b_resid,
|
||||
done_ccb->csio.tag_action & 0xf,
|
||||
(bp->b_flags & B_READ) ? DEVSTAT_READ
|
||||
: DEVSTAT_WRITE);
|
||||
|
||||
biodone(bp);
|
||||
break;
|
||||
}
|
||||
case PT_CCB_WAITING:
|
||||
/* Caller will release the CCB */
|
||||
wakeup(&done_ccb->ccb_h.cbfcnp);
|
||||
return;
|
||||
}
|
||||
xpt_release_ccb(done_ccb);
|
||||
}
|
||||
|
||||
static int
|
||||
pterror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
|
||||
{
|
||||
struct pt_softc *softc;
|
||||
struct cam_periph *periph;
|
||||
|
||||
periph = xpt_path_periph(ccb->ccb_h.path);
|
||||
softc = (struct pt_softc *)periph->softc;
|
||||
|
||||
return(cam_periph_error(ccb, cam_flags, sense_flags,
|
||||
&softc->saved_ccb));
|
||||
}
|
||||
|
||||
void
|
||||
scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries,
|
||||
void (*cbfcnp)(struct cam_periph *, union ccb *),
|
||||
u_int tag_action, int readop, u_int byte2,
|
||||
u_int32_t xfer_len, u_int8_t *data_ptr, u_int8_t sense_len,
|
||||
u_int32_t timeout)
|
||||
{
|
||||
struct scsi_send_receive *scsi_cmd;
|
||||
|
||||
scsi_cmd = (struct scsi_send_receive *)&csio->cdb_io.cdb_bytes;
|
||||
scsi_cmd->opcode = readop ? RECEIVE : SEND;
|
||||
scsi_cmd->byte2 = byte2;
|
||||
scsi_ulto3b(xfer_len, scsi_cmd->xfer_len);
|
||||
scsi_cmd->control = 0;
|
||||
|
||||
cam_fill_csio(csio,
|
||||
retries,
|
||||
cbfcnp,
|
||||
/*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT,
|
||||
tag_action,
|
||||
data_ptr,
|
||||
xfer_len,
|
||||
sense_len,
|
||||
sizeof(*scsi_cmd),
|
||||
timeout);
|
||||
}
|
48
sys/cam/scsi/scsi_pt.h
Normal file
48
sys/cam/scsi/scsi_pt.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Structure and function declartaions for Processor type devices.
|
||||
*
|
||||
* Copyright (c) 1998 Justin T. Gibbs
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification, immediately at the beginning of the file.
|
||||
* 2. 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef _SCSI_SCSI_PT_H
|
||||
#define _SCSI_SCSI_PT_H 1
|
||||
|
||||
struct scsi_send_receive
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t byte2;
|
||||
u_int8_t xfer_len[3];
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
/*
|
||||
* Opcodes
|
||||
*/
|
||||
#define RECEIVE 0x08
|
||||
#define SEND 0x0A
|
||||
|
||||
#endif /* _SCSI_SCSI_PT_H */
|
2337
sys/cam/scsi/scsi_sa.c
Normal file
2337
sys/cam/scsi/scsi_sa.c
Normal file
File diff suppressed because it is too large
Load Diff
254
sys/cam/scsi/scsi_sa.h
Normal file
254
sys/cam/scsi/scsi_sa.h
Normal file
@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Structure and function declartaions for the
|
||||
* SCSI Sequential Access Peripheral driver for CAM.
|
||||
*
|
||||
* Copyright (c) 1997 Justin T. Gibbs
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification, immediately at the beginning of the file.
|
||||
* 2. 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef _SCSI_SCSI_SA_H
|
||||
#define _SCSI_SCSI_SA_H 1
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
struct scsi_read_block_limits
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t byte2;
|
||||
u_int8_t unused[3];
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
struct scsi_read_block_limits_data
|
||||
{
|
||||
u_int8_t gran;
|
||||
#define RBL_GRAN_MASK 0x1F
|
||||
#define RBL_GRAN(rblim) ((rblim)->gran & RBL_GRAN_MASK)
|
||||
u_int8_t maximum[3];
|
||||
u_int8_t minimum[2];
|
||||
};
|
||||
|
||||
struct scsi_sa_rw
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t sli_fixed;
|
||||
#define SAR_SLI 0x02
|
||||
#define SARW_FIXED 0x01
|
||||
u_int8_t length[3];
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
struct scsi_load_unload
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t immediate;
|
||||
#define SLU_IMMED 0x01
|
||||
u_int8_t reserved[2];
|
||||
u_int8_t eot_reten_load;
|
||||
#define SLU_EOT 0x04
|
||||
#define SLU_RETEN 0x02
|
||||
#define SLU_LOAD 0x01
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
struct scsi_rewind
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t immediate;
|
||||
#define SREW_IMMED 0x01
|
||||
u_int8_t reserved[3];
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
SS_BLOCKS,
|
||||
SS_FILEMARKS,
|
||||
SS_SEQFILEMARKS,
|
||||
SS_EOD,
|
||||
SS_SETMARKS,
|
||||
SS_SEQSETMARKS
|
||||
} scsi_space_code;
|
||||
|
||||
struct scsi_space
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t code;
|
||||
#define SREW_IMMED 0x01
|
||||
u_int8_t count[3];
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
struct scsi_write_filemarks
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t byte2;
|
||||
#define SWFMRK_IMMED 0x01
|
||||
#define SWFMRK_WSMK 0x02
|
||||
u_int8_t num_marks[3];
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
/*
|
||||
* Reserve and release unit have the same exact cdb format, but different
|
||||
* opcodes.
|
||||
*/
|
||||
struct scsi_reserve_release_unit
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t lun_thirdparty;
|
||||
#define SRRU_LUN_MASK 0xE0
|
||||
#define SRRU_3RD_PARTY 0x10
|
||||
#define SRRU_3RD_SHAMT 1
|
||||
#define SRRU_3RD_MASK 0xE
|
||||
u_int8_t reserved[3];
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
/*
|
||||
* Erase a tape
|
||||
*/
|
||||
struct scsi_erase
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t lun_imm_long;
|
||||
#define SE_LUN_MASK 0xE0
|
||||
#define SE_LONG 0x1
|
||||
#define SE_IMMED 0x2
|
||||
u_int8_t reserved[3];
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
/*
|
||||
* Dev specific mode page masks.
|
||||
*/
|
||||
#define SMH_SA_WP 0x80
|
||||
#define SMH_SA_BUF_MODE_MASK 0x70
|
||||
#define SMH_SA_BUF_MODE_NOBUF 0x00
|
||||
#define SMH_SA_BUF_MODE_SIBUF 0x10 /* Single-Initiator buffering */
|
||||
#define SMH_SA_BUF_MODE_MIBUF 0x20 /* Multi-Initiator buffering */
|
||||
#define SMH_SA_SPEED_MASK 0x0F
|
||||
#define SMH_SA_SPEED_DEFAULT 0x00
|
||||
|
||||
/*
|
||||
* Sequential-access specific mode page numbers.
|
||||
*/
|
||||
#define SA_DATA_COMPRESSION_PAGE 0x0f
|
||||
#define SA_DEVICE_CONFIGURATION_PAGE 0x10
|
||||
#define SA_MEDIUM_PARTITION_PAGE_1 0x11
|
||||
#define SA_MEDIUM_PARTITION_PAGE_2 0x12
|
||||
#define SA_MEDIUM_PARTITION_PAGE_3 0x13
|
||||
#define SA_MEDIUM_PARTITION_PAGE_4 0x14
|
||||
|
||||
/*
|
||||
* Mode page definitions.
|
||||
*/
|
||||
|
||||
struct scsi_data_compression_page {
|
||||
u_int8_t page_code;
|
||||
u_int8_t page_length;
|
||||
#define SA_DCP_DCE 0x80 /* Data compression enable */
|
||||
#define SA_DCP_DCC 0x40 /* Data compression capable */
|
||||
u_int8_t dce_and_dcc;
|
||||
#define SA_DCP_DDE 0x80 /* Data decompression enable */
|
||||
#define SA_DCP_RED_MASK 0x60 /* Report Exception on Decomp. */
|
||||
#define SA_DCP_RED_SHAMT 5
|
||||
#define SA_DCP_RED_0 0x00
|
||||
#define SA_DCP_RED_1 0x20
|
||||
#define SA_DCP_RED_2 0x40
|
||||
u_int8_t dde_and_red;
|
||||
u_int8_t comp_algorithm[4];
|
||||
u_int8_t decomp_algorithm[4];
|
||||
u_int8_t reserved[4];
|
||||
};
|
||||
|
||||
/*
|
||||
* Opcodes
|
||||
*/
|
||||
#define REWIND 0x01
|
||||
#define READ_BLOCK_LIMITS 0x05
|
||||
#define SA_READ 0x08
|
||||
#define SA_WRITE 0x0A
|
||||
#define WRITE_FILEMARKS 0x10
|
||||
#define SPACE 0x11
|
||||
#define RESERVE_UNIT 0x16
|
||||
#define RELEASE_UNIT 0x17
|
||||
#define ERASE 0x19
|
||||
#define LOAD_UNLOAD 0x1B
|
||||
|
||||
__BEGIN_DECLS
|
||||
void scsi_read_block_limits(struct ccb_scsiio *, u_int32_t,
|
||||
void (*cbfcnp)(struct cam_periph *, union ccb *),
|
||||
u_int8_t, struct scsi_read_block_limits_data *,
|
||||
u_int8_t , u_int32_t);
|
||||
|
||||
void scsi_sa_read_write(struct ccb_scsiio *csio, u_int32_t retries,
|
||||
void (*cbfcnp)(struct cam_periph *, union ccb *),
|
||||
u_int8_t tag_action, int readop, int sli,
|
||||
int fixed, u_int32_t length, u_int8_t *data_ptr,
|
||||
u_int32_t dxfer_len, u_int8_t sense_len,
|
||||
u_int32_t timeout);
|
||||
|
||||
void scsi_rewind(struct ccb_scsiio *csio, u_int32_t retries,
|
||||
void (*cbfcnp)(struct cam_periph *, union ccb *),
|
||||
u_int8_t tag_action, int immediate, u_int8_t sense_len,
|
||||
u_int32_t timeout);
|
||||
|
||||
void scsi_space(struct ccb_scsiio *csio, u_int32_t retries,
|
||||
void (*cbfcnp)(struct cam_periph *, union ccb *),
|
||||
u_int8_t tag_action, scsi_space_code code,
|
||||
u_int32_t count, u_int8_t sense_len, u_int32_t timeout);
|
||||
|
||||
void scsi_load_unload(struct ccb_scsiio *csio, u_int32_t retries,
|
||||
void (*cbfcnp)(struct cam_periph *, union ccb *),
|
||||
u_int8_t tag_action, int immediate, int eot,
|
||||
int reten, int load, u_int8_t sense_len,
|
||||
u_int32_t timeout);
|
||||
|
||||
void scsi_write_filemarks(struct ccb_scsiio *csio, u_int32_t retries,
|
||||
void (*cbfcnp)(struct cam_periph *, union ccb *),
|
||||
u_int8_t tag_action, int immediate, int setmark,
|
||||
u_int32_t num_marks, u_int8_t sense_len,
|
||||
u_int32_t timeout);
|
||||
|
||||
void scsi_reserve_release_unit(struct ccb_scsiio *csio, u_int32_t retries,
|
||||
void (*cbfcnp)(struct cam_periph *,
|
||||
union ccb *), u_int8_t tag_action,
|
||||
int third_party, int third_party_id,
|
||||
u_int8_t sense_len, u_int32_t timeout,
|
||||
int reserve);
|
||||
|
||||
void scsi_erase(struct ccb_scsiio *csio, u_int32_t retries,
|
||||
void (*cbfcnp)(struct cam_periph *, union ccb *),
|
||||
u_int8_t tag_action, int immediate, int long_erase,
|
||||
u_int8_t sense_len, u_int32_t timeout);
|
||||
|
||||
void scsi_data_comp_page(struct scsi_data_compression_page *page,
|
||||
u_int8_t dce, u_int8_t dde, u_int8_t red,
|
||||
u_int32_t comp_algorithm,
|
||||
u_int32_t decomp_algorithm);
|
||||
__END_DECLS
|
||||
|
||||
#endif /* _SCSI_SCSI_SA_H */
|
1459
sys/cam/scsi/scsi_target.c
Normal file
1459
sys/cam/scsi/scsi_target.c
Normal file
File diff suppressed because it is too large
Load Diff
103
sys/cam/scsi/scsi_targetio.h
Normal file
103
sys/cam/scsi/scsi_targetio.h
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Ioctl definitions for the Target Mode SCSI Proccessor Target driver for CAM.
|
||||
*
|
||||
* Copyright (c) 1998 Justin T. Gibbs.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification, immediately at the beginning of the file.
|
||||
* 2. 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef _CAM_SCSI_SCSI_TARGETIO_H_
|
||||
#define _CAM_SCSI_SCSI_TARGETIO_H_
|
||||
#ifndef KERNEL
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include <sys/ioccom.h>
|
||||
|
||||
#include <cam/cam.h>
|
||||
#include <cam/cam_ccb.h>
|
||||
|
||||
/* Determine and clear exception state in the driver */
|
||||
typedef enum {
|
||||
TARG_EXCEPT_NONE = 0x00,
|
||||
TARG_EXCEPT_DEVICE_INVALID = 0x01,
|
||||
TARG_EXCEPT_BDR_RECEIVED = 0x02,
|
||||
TARG_EXCEPT_BUS_RESET_SEEN = 0x04,
|
||||
TARG_EXCEPT_UNKNOWN_ATIO = 0x08,
|
||||
} targ_exception;
|
||||
|
||||
#define TARGIOCFETCHEXCEPTION _IOR('C', 1, targ_exception)
|
||||
#define TARGIOCCLEAREXCEPTION _IOW('C', 2, targ_exception)
|
||||
|
||||
/*
|
||||
* Retreive an Accept Target I/O CCB for a command that is not handled
|
||||
* directly by the kernel target driver.
|
||||
*/
|
||||
#define TARGIOCFETCHATIO _IOR('C', 3, struct ccb_accept_tio)
|
||||
|
||||
/*
|
||||
* Used for responding to incoming ATIO requests. XPT_CONTINUE_TARG_IO
|
||||
* operations are the norm, but ccb types for manipulating the device
|
||||
* queue, etc. can also be used if error handling is to be performed by the
|
||||
* user land process.
|
||||
*/
|
||||
#define TARGIOCCOMMAND _IOWR('C', 4, union ccb)
|
||||
|
||||
|
||||
typedef enum {
|
||||
UA_NONE = 0x00,
|
||||
UA_POWER_ON = 0x01,
|
||||
UA_BUS_RESET = 0x02
|
||||
} ua_types;
|
||||
|
||||
typedef enum {
|
||||
CA_NONE = 0x00,
|
||||
CA_UNIT_ATTN = 0x01,
|
||||
CA_CMD_SENSE = 0x02
|
||||
} ca_types;
|
||||
|
||||
struct initiator_state {
|
||||
ua_types pending_ua;
|
||||
ca_types pending_ca;
|
||||
struct scsi_sense_data sense_data;
|
||||
};
|
||||
|
||||
struct ioc_initiator_state {
|
||||
u_int initiator_id;
|
||||
struct initiator_state istate;
|
||||
};
|
||||
|
||||
/*
|
||||
* Get and Set Contingent Allegiance and Unit Attention state
|
||||
* presented by the target driver. This is usually used to
|
||||
* properly report and error condition in response to an incoming
|
||||
* ATIO request handled by the userland process.
|
||||
*
|
||||
* The initiator_id must be properly initialized in the ioc_initiator_state
|
||||
* structure before calling TARGIOCGETISTATE.
|
||||
*/
|
||||
#define TARGIOCGETISTATE _IOWR('C', 6, struct ioc_initiator_state)
|
||||
#define TARGIOCSETISTATE _IOW('C', 5, struct ioc_initiator_state)
|
||||
|
||||
#endif /* _CAM_SCSI_SCSI_TARGETIO_H_ */
|
Loading…
Reference in New Issue
Block a user