/* * (C) Copyright IBM Corp. 2004, 2005 All Rights Reserved. * * spc3.h * * Tool to make use of a SCSI-feature called Asymmetric Logical Unit Access. * It determines the ALUA state of a device and prints a priority value to * stdout. * * Author(s): Jan Kunigk * S. Bader * * This file is released under the GPL. */ #ifndef __SPC3_H__ #define __SPC3_H__ /*============================================================================= * Some helper functions for getting and setting 16 and 32 bit values. *============================================================================= */ static inline unsigned short get_uint16(unsigned char *p) { return (p[0] << 8) + p[1]; } static inline void set_uint16(unsigned char *p, unsigned short v) { p[0] = (v >> 8) & 0xff; p[1] = v & 0xff; } static inline unsigned int get_uint32(unsigned char *p) { return (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]; } static inline void set_uint32(unsigned char *p, unsigned int v) { p[0] = (v >> 24) & 0xff; p[1] = (v >> 16) & 0xff; p[2] = (v >> 8) & 0xff; p[3] = v & 0xff; } /*============================================================================= * Definitions to support the standard inquiry command as defined in SPC-3. * If the evpd (enable vital product data) bit is set the data that will be * returned is selected by the page field. This field must be 0 if the evpd * bit is not set. *============================================================================= */ #define OPERATION_CODE_INQUIRY 0x12 struct inquiry_command { unsigned char op; unsigned char b1; /* xxxxxx.. = reserved */ /* ......x. = obsolete */ /* .......x = evpd */ unsigned char page; unsigned char length[2]; unsigned char control; } __attribute__((packed)); static inline void inquiry_command_set_evpd(struct inquiry_command *ic) { ic->b1 |= 1; } /*----------------------------------------------------------------------------- * Data returned by the standard inquiry command. *----------------------------------------------------------------------------- * * Peripheral qualifier codes. */ #define PQ_CONNECTED 0x0 #define PQ_DISCONNECTED 0x1 #define PQ_UNSUPPORTED 0x3 /* Defined peripheral device types. */ #define PDT_DIRECT_ACCESS 0x00 #define PDT_SEQUENTIAL_ACCESS 0x01 #define PDT_PRINTER 0x02 #define PDT_PROCESSOR 0x03 #define PDT_WRITE_ONCE 0x04 #define PDT_CD_DVD 0x05 #define PDT_SCANNER 0x06 #define PDT_OPTICAL_MEMORY 0x07 #define PDT_MEDIUM_CHANGER 0x08 #define PDT_COMMUNICATIONS 0x09 #define PDT_STORAGE_ARRAY_CONTROLLER 0x0c #define PDT_ENCLOSURE_SERVICES 0x0d #define PDT_SIMPLIFIED_DIRECT_ACCESS 0x0e #define PDT_OPTICAL_CARD_READER_WRITER 0x0f #define PDT_BRIDGE_CONTROLLER 0x10 #define PDT_OBJECT_BASED 0x11 #define PDT_AUTOMATION_INTERFACE 0x12 #define PDT_LUN 0x1e #define PDT_UNKNOWN 0x1f /* Defined version codes. */ #define VERSION_NONE 0x00 #define VERSION_SPC 0x03 #define VERSION_SPC2 0x04 #define VERSION_SPC3 0x05 /* Defined TPGS field values. */ #define TPGS_NONE 0x0 #define TPGS_IMPLICIT 0x1 #define TPGS_EXPLICIT 0x2 #define TPGS_BOTH 0x3 struct inquiry_data { unsigned char b0; /* xxx..... = peripheral_qualifier */ /* ...xxxxx = peripheral_device_type */ unsigned char b1; /* x....... = removable medium */ /* .xxxxxxx = reserverd */ unsigned char version; unsigned char b3; /* xx...... = obsolete */ /* ..x..... = normal aca supported */ /* ...x.... = hirarchichal lun supp. */ /* ....xxxx = response format */ /* 2 is spc-3 format */ unsigned char length; unsigned char b5; /* x....... = storage controller */ /* component supported */ /* .x...... = access controls coord. */ /* ..xx.... = target port group supp.*/ /* ....x... = third party copy supp. */ /* .....xx. = reserved */ /* .......x = protection info supp. */ unsigned char b6; /* x....... = bque */ /* .x...... = enclosure services sup.*/ /* ..x..... = vs1 */ /* ...x.... = multiport support */ /* ....x... = medium changer */ /* .....xx. = obsolete */ /* .......x = add16 */ unsigned char b7; /* xx...... = obsolete */ /* ..x..... = wbus16 */ /* ...x.... = sync */ /* ....x... = linked commands supp. */ /* .....x.. = obsolete */ /* ......x. = command queue support */ /* .......x = vs2 */ unsigned char vendor_identification[8]; unsigned char product_identification[16]; unsigned char product_revision[4]; unsigned char vendor_specific[20]; unsigned char b56; /* xxxx.... = reserved */ /* ....xx.. = clocking */ /* ......x. = qas */ /* .......x = ius */ unsigned char reserved4; unsigned char version_descriptor[8][2]; unsigned char reserved5[22]; unsigned char vendor_parameters[0]; } __attribute__((packed)); static inline int inquiry_data_get_tpgs(struct inquiry_data *id) { return (id->b5 >> 4) & 3; } /*----------------------------------------------------------------------------- * Inquiry data returned when requesting vital product data page 0x83. *----------------------------------------------------------------------------- */ #define CODESET_BINARY 0x1 #define CODESET_ACSII 0x2 #define CODESET_UTF8 0x3 #define ASSOCIATION_UNIT 0x0 #define ASSOCIATION_PORT 0x1 #define ASSOCIATION_DEVICE 0x2 #define IDTYPE_VENDOR_SPECIFIC 0x0 #define IDTYPE_T10_VENDOR_ID 0x1 #define IDTYPE_EUI64 0x2 #define IDTYPE_NAA 0x3 #define IDTYPE_RELATIVE_TPG_ID 0x4 #define IDTYPE_TARGET_PORT_GROUP 0x5 #define IDTYPE_LUN_GROUP 0x6 #define IDTYPE_MD5_LUN_ID 0x7 #define IDTYPE_SCSI_NAME_STRING 0x8 struct vpd83_tpg_dscr { unsigned char reserved1[2]; unsigned char tpg[2]; } __attribute__((packed)); struct vpd83_dscr { unsigned char b0; /* xxxx.... = protocol id */ /* ....xxxx = codeset */ unsigned char b1; /* x....... = protocol id valid */ /* .x...... = reserved */ /* ..xx.... = association */ /* ....xxxx = id type */ unsigned char reserved2; unsigned char length; /* size-4 */ unsigned char data[0]; } __attribute__((packed)); static inline int vpd83_dscr_istype(struct vpd83_dscr *d, unsigned char type) { return ((d->b1 & 7) == type); } struct vpd83_data { unsigned char b0; /* xxx..... = peripheral_qualifier */ /* ...xxxxx = peripheral_device_type */ unsigned char page_code; /* 0x83 */ unsigned char length[2]; /* size-4 */ struct vpd83_dscr data[0]; } __attribute__((packed)); /*----------------------------------------------------------------------------- * This macro should be used to walk through all identification descriptors * defined in the code page 0x83. * The argument p is a pointer to the code page 0x83 data and d is used to * point to the current descriptor. *----------------------------------------------------------------------------- */ #define FOR_EACH_VPD83_DSCR(p, d) \ for( \ d = p->data; \ (((char *) d) - ((char *) p)) < \ get_uint16(p->length); \ d = (struct vpd83_dscr *) \ ((char *) d + d->length + 4) \ ) /*============================================================================= * The following stuctures and macros are used to call the report target port * groups command defined in SPC-3. * This command is used to get information about the target port groups (which * states are supported, which ports belong to this group, and so on) and the * current state of each target port group. *============================================================================= */ #define OPERATION_CODE_RTPG 0xa3 #define SERVICE_ACTION_RTPG 0x0a struct rtpg_command { unsigned char op; /* 0xa3 */ unsigned char b1; /* xxx..... = reserved */ /* ...xxxxx = service action (0x0a) */ unsigned char reserved2[4]; unsigned char length[4]; unsigned char reserved3; unsigned char control; } __attribute__((packed)); static inline void rtpg_command_set_service_action(struct rtpg_command *cmd) { cmd->b1 = (cmd->b1 & 0xe0) | SERVICE_ACTION_RTPG; } struct rtpg_tp_dscr { unsigned char obsolete1[2]; /* The Relative Target Port Identifier of a target port. */ unsigned char rtpi[2]; } __attribute__((packed)); #define AAS_OPTIMIZED 0x0 #define AAS_NON_OPTIMIZED 0x1 #define AAS_STANDBY 0x2 #define AAS_UNAVAILABLE 0x3 #define AAS_TRANSITIONING 0xf #define TPG_STATUS_NONE 0x0 #define TPG_STATUS_SET 0x1 #define TPG_STATUS_IMPLICIT_CHANGE 0x2 struct rtpg_tpg_dscr { unsigned char b0; /* x....... = pref(ered) port */ /* .xxx.... = reserved */ /* ....xxxx = asymetric access state */ unsigned char b1; /* xxxx.... = reserved */ /* ....x... = unavailable support */ /* .....x.. = standby support */ /* ......x. = non-optimized support */ /* .......x = optimized support */ unsigned char tpg[2]; unsigned char reserved3; unsigned char status; unsigned char vendor_unique; unsigned char port_count; struct rtpg_tp_dscr data[0]; } __attribute__((packed)); static inline int rtpg_tpg_dscr_get_aas(struct rtpg_tpg_dscr *d) { return (d->b0 & 0x0f); } struct rtpg_data { unsigned char length[4]; /* size-4 */ struct rtpg_tpg_dscr data[0]; } __attribute__((packed)); #define RTPG_FOR_EACH_PORT_GROUP(p, g) \ for( \ g = &(p->data[0]); \ (((char *) g) - ((char *) p)) < get_uint32(p->length); \ g = (struct rtpg_tpg_dscr *) ( \ ((char *) g) + \ sizeof(struct rtpg_tpg_dscr) + \ g->port_count * sizeof(struct rtpg_tp_dscr) \ ) \ ) #endif /* __SPC3_H__ */