Update chio(1) and ch(4) to support reporting element designators.

This allows mapping a tape drive in a changer (as reported by
'chio status') to a sa(4) driver instance by comparing the
serial numbers.

The designators can be ASCII (which is printed out directly), binary
(which is printed in hex format) or UTF-8, which is printed in either
native UTF-8 format if the terminal can support it, or in %XX notation
for non-ASCII characters.  Thanks to Hiroki Sato <hrs@> for the
explaining UTF-8 printing and example UTF-8 printing code.

chio.h:		Modify the changer_element_status structure to add new
		fields and definitions from the SMC3r16 spec.

		Rename the original CHIOGSTATUS ioctl to OCHIOGTATUS and
		define a new CHIOGSTATUS ioctl.

		Clean up some tab/space issues.

chio.c: 	For the 'status' subcommand, print the designator field
		if it is supplied by a device.

scsi_ch.h:	Add new flags for DVCID and CURDATA to the READ
		ELEMENT STATUS command structure.

		Add a read_element_status_device_id structure
		for the data fields in the new standard. Add new
		unions, dt_or_obsolete and voltage_devid, to hold
		and address data from either SCSI-2 or newer devices.

scsi_ch.c:	Implement support for fetching device IDs with READ
		ELEMENT STATUS data.

		Add new arguments to scsi_read_element_status() to
		allow the user to request the DVCID and CURDATA bits.
		This isn't compiled into libcam (it's only an internal
		kernel interface), so we don't need any special
		handling for the API change.

		If the user issues the new CHIOGSTATUS ioctl, copy all of
		the available element status data out.  If he issues the
		OCHIOGSTATUS ioctl, we don't copy the new fields in the
		structure.

		Fix a bug in chopen() that would result in the peripheral
		never getting unheld if chgetparams() failed.

Sponsored by:	Spectra Logic
Submitted by:	Po-Li Soong
MFC After:	1 week
This commit is contained in:
ken 2013-04-19 20:03:51 +00:00
parent 120125784a
commit 9a543047eb
4 changed files with 380 additions and 75 deletions

View File

@ -54,6 +54,8 @@ __FBSDID("$FreeBSD$");
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <langinfo.h>
#include <locale.h>
#include "defs.h"
#include "pathnames.h"
@ -81,6 +83,7 @@ static int do_status(const char *, int, char **);
static int do_ielem(const char *, int, char **);
static int do_return(const char *, int, char **);
static int do_voltag(const char *, int, char **);
static void print_designator(const char *, u_int8_t, u_int8_t);
#ifndef CHET_VT
#define CHET_VT 10 /* Completely Arbitrary */
@ -723,6 +726,10 @@ do_status(const char *cname, int argc, char **argv)
putchar('?');
putchar('>');
}
if (ces->ces_designator_length > 0)
print_designator(ces->ces_designator,
ces->ces_code_set,
ces->ces_designator_length);
putchar('\n');
}
@ -1177,3 +1184,66 @@ usage(void)
"arg1 arg2 [arg3 [...]]\n", getprogname());
exit(1);
}
#define UTF8CODESET "UTF-8"
static void
print_designator(const char *designator, u_int8_t code_set,
u_int8_t designator_length)
{
printf(" serial number: <");
switch (code_set) {
case CES_CODE_SET_ASCII: {
/*
* The driver insures that the string is always NUL terminated.
*/
printf("%s", designator);
break;
}
case CES_CODE_SET_UTF_8: {
char *cs_native;
setlocale(LC_ALL, "");
cs_native = nl_langinfo(CODESET);
/* See if we can natively print UTF-8 */
if (strcmp(cs_native, UTF8CODESET) == 0)
cs_native = NULL;
if (cs_native == NULL) {
/* We can natively print UTF-8, so use printf. */
printf("%s", designator);
} else {
int i;
/*
* We can't natively print UTF-8. We should
* convert it to the terminal's codeset, but that
* requires iconv(3) and FreeBSD doesn't have
* iconv(3) in the base system yet. So we use %XX
* notation for non US-ASCII characters instead.
*/
for (i = 0; i < designator_length &&
designator[i] != '\0'; i++) {
if ((unsigned char)designator[i] < 0x80)
printf("%c", designator[i]);
else
printf("%%%02x",
(unsigned char)designator[i]);
}
}
break;
}
case CES_CODE_SET_BINARY: {
int i;
for (i = 0; i < designator_length; i++)
printf("%02X%s", designator[i],
(i == designator_length - 1) ? "" : " ");
break;
}
default:
break;
}
printf(">");
}

View File

@ -194,12 +194,14 @@ static int chexchange(struct cam_periph *periph,
static int chposition(struct cam_periph *periph,
struct changer_position *cp);
static int chgetelemstatus(struct cam_periph *periph,
int scsi_version, u_long cmd,
struct changer_element_status_request *csr);
static int chsetvoltag(struct cam_periph *periph,
struct changer_set_voltag_request *csvr);
static int chielem(struct cam_periph *periph,
unsigned int timeout);
static int chgetparams(struct cam_periph *periph);
static int chscsiversion(struct cam_periph *periph);
static struct periph_driver chdriver =
{
@ -474,6 +476,7 @@ chopen(struct cdev *dev, int flags, int fmt, struct thread *td)
* Load information about this changer device into the softc.
*/
if ((error = chgetparams(periph)) != 0) {
cam_periph_unhold(periph);
cam_periph_release_locked(periph);
cam_periph_unlock(periph);
return(error);
@ -772,6 +775,7 @@ chioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
switch (cmd) {
case CHIOGPICKER:
case CHIOGPARAMS:
case OCHIOGSTATUS:
case CHIOGSTATUS:
break;
@ -824,10 +828,26 @@ chioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
error = chielem(periph, *(unsigned int *)addr);
break;
case OCHIOGSTATUS:
{
error = chgetelemstatus(periph, SCSI_REV_2, cmd,
(struct changer_element_status_request *)addr);
break;
}
case CHIOGSTATUS:
{
error = chgetelemstatus(periph,
(struct changer_element_status_request *) addr);
int scsi_version;
scsi_version = chscsiversion(periph);
if (scsi_version >= SCSI_REV_0) {
error = chgetelemstatus(periph, scsi_version, cmd,
(struct changer_element_status_request *)addr);
}
else { /* unable to determine the SCSI version */
cam_periph_unlock(periph);
return (ENXIO);
}
break;
}
@ -1034,18 +1054,20 @@ copy_voltag(struct changer_voltag *uvoltag, struct volume_tag *voltag)
}
/*
* Copy an an element status descriptor to a user-mode
* Copy an element status descriptor to a user-mode
* changer_element_status structure.
*/
static void
static void
copy_element_status(struct ch_softc *softc,
u_int16_t flags,
struct read_element_status_descriptor *desc,
struct changer_element_status *ces)
struct changer_element_status *ces,
int scsi_version)
{
u_int16_t eaddr = scsi_2btoul(desc->eaddr);
u_int16_t et;
struct volume_tag *pvol_tag = NULL, *avol_tag = NULL;
struct read_element_status_device_id *devid = NULL;
ces->ces_int_addr = eaddr;
/* set up logical address in element status */
@ -1076,7 +1098,7 @@ copy_element_status(struct ch_softc *softc,
if ((softc->sc_firsts[et] <= eaddr)
&& ((softc->sc_firsts[et] + softc->sc_counts[et])
> eaddr)) {
ces->ces_source_addr =
ces->ces_source_addr =
eaddr - softc->sc_firsts[et];
ces->ces_source_type = et;
ces->ces_flags |= CES_SOURCE_VALID;
@ -1089,27 +1111,92 @@ copy_element_status(struct ch_softc *softc,
"address %ud to a valid element type\n",
eaddr);
}
/*
* pvoltag and avoltag are common between SCSI-2 and later versions
*/
if (flags & READ_ELEMENT_STATUS_PVOLTAG)
copy_voltag(&(ces->ces_pvoltag), &(desc->pvoltag));
pvol_tag = &desc->voltag_devid.pvoltag;
if (flags & READ_ELEMENT_STATUS_AVOLTAG)
copy_voltag(&(ces->ces_avoltag), &(desc->avoltag));
if (desc->dt_scsi_flags & READ_ELEMENT_STATUS_DT_IDVALID) {
ces->ces_flags |= CES_SCSIID_VALID;
ces->ces_scsi_id = desc->dt_scsi_addr;
avol_tag = (flags & READ_ELEMENT_STATUS_PVOLTAG) ?
&desc->voltag_devid.voltag[1] :&desc->voltag_devid.pvoltag;
/*
* For SCSI-3 and later, element status can carry designator and
* other information.
*/
if (scsi_version >= SCSI_REV_SPC) {
if ((flags & READ_ELEMENT_STATUS_PVOLTAG) ^
(flags & READ_ELEMENT_STATUS_AVOLTAG))
devid = &desc->voltag_devid.pvol_and_devid.devid;
else if (!(flags & READ_ELEMENT_STATUS_PVOLTAG) &&
!(flags & READ_ELEMENT_STATUS_AVOLTAG))
devid = &desc->voltag_devid.devid;
else /* Have both PVOLTAG and AVOLTAG */
devid = &desc->voltag_devid.vol_tags_and_devid.devid;
}
if (desc->dt_scsi_addr & READ_ELEMENT_STATUS_DT_LUVALID) {
ces->ces_flags |= CES_LUN_VALID;
ces->ces_scsi_lun =
desc->dt_scsi_flags & READ_ELEMENT_STATUS_DT_LUNMASK;
if (pvol_tag)
copy_voltag(&(ces->ces_pvoltag), pvol_tag);
if (avol_tag)
copy_voltag(&(ces->ces_pvoltag), avol_tag);
if (devid != NULL) {
if (devid->designator_length > 0) {
bcopy((void *)devid->designator,
(void *)ces->ces_designator,
devid->designator_length);
ces->ces_designator_length = devid->designator_length;
/*
* Make sure we are always NUL terminated. The
* buffer should be sized for the maximum
* designator length plus 1, but this will make sure
* there is always a NUL at the end. This won't
* matter for the binary code set, since the user
* will only pay attention to the length field.
*/
ces->ces_designator[
MIN(sizeof(ces->ces_designator) - 1,
devid->designator_length)]= '\0';
}
if (devid->piv_assoc_designator_type &
READ_ELEMENT_STATUS_PIV_SET) {
ces->ces_flags |= CES_PIV;
ces->ces_protocol_id =
READ_ELEMENT_STATUS_PROTOCOL_ID(
devid->prot_code_set);
}
ces->ces_code_set =
READ_ELEMENT_STATUS_CODE_SET(devid->prot_code_set);
ces->ces_assoc = READ_ELEMENT_STATUS_ASSOCIATION(
devid->piv_assoc_designator_type);
ces->ces_designator_type = READ_ELEMENT_STATUS_DESIGNATOR_TYPE(
devid->piv_assoc_designator_type);
} else if (scsi_version > SCSI_REV_2) {
/* SCSI-SPC and No devid, no designator */
ces->ces_designator_length = 0;
ces->ces_designator[0] = '\0';
ces->ces_protocol_id = CES_PROTOCOL_ID_FCP_4;
}
if (scsi_version <= SCSI_REV_2) {
if (desc->dt_or_obsolete.scsi_2.dt_scsi_flags &
READ_ELEMENT_STATUS_DT_IDVALID) {
ces->ces_flags |= CES_SCSIID_VALID;
ces->ces_scsi_id =
desc->dt_or_obsolete.scsi_2.dt_scsi_addr;
}
if (desc->dt_or_obsolete.scsi_2.dt_scsi_addr &
READ_ELEMENT_STATUS_DT_LUVALID) {
ces->ces_flags |= CES_LUN_VALID;
ces->ces_scsi_lun =
desc->dt_or_obsolete.scsi_2.dt_scsi_flags &
READ_ELEMENT_STATUS_DT_LUNMASK;
}
}
}
static int
chgetelemstatus(struct cam_periph *periph,
chgetelemstatus(struct cam_periph *periph, int scsi_version, u_long cmd,
struct changer_element_status_request *cesr)
{
struct read_element_status_header *st_hdr;
@ -1155,6 +1242,8 @@ chgetelemstatus(struct cam_periph *periph,
/* tag_action */ MSG_SIMPLE_Q_TAG,
/* voltag */ want_voltags,
/* sea */ softc->sc_firsts[chet],
/* dvcid */ 1,
/* curdata */ 1,
/* count */ 1,
/* data_ptr */ data,
/* dxfer_len */ 1024,
@ -1177,7 +1266,6 @@ chgetelemstatus(struct cam_periph *periph,
size = sizeof(struct read_element_status_header) +
sizeof(struct read_element_status_page_header) +
(desclen * cesr->cesr_element_count);
/*
* Reallocate storage for descriptors and get them from the
* device.
@ -1193,12 +1281,14 @@ chgetelemstatus(struct cam_periph *periph,
/* voltag */ want_voltags,
/* sea */ softc->sc_firsts[chet]
+ cesr->cesr_element_base,
/* dvcid */ 1,
/* curdata */ 1,
/* count */ cesr->cesr_element_count,
/* data_ptr */ data,
/* dxfer_len */ size,
/* sense_len */ SSD_FULL_SIZE,
/* timeout */ CH_TIMEOUT_READ_ELEMENT_STATUS);
error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO,
/*sense_flags*/ SF_RETRY_UA,
softc->device_stats);
@ -1231,18 +1321,41 @@ chgetelemstatus(struct cam_periph *periph,
* Set up the individual element status structures
*/
for (i = 0; i < avail; ++i) {
struct changer_element_status *ces = &(user_data[i]);
struct changer_element_status *ces;
copy_element_status(softc, pg_hdr->flags, desc, ces);
/*
* In the changer_element_status structure, fields from
* the beginning to the field of ces_scsi_lun are common
* between SCSI-2 and SCSI-3, while all the rest are new
* from SCSI-3. In order to maintain backward compatibility
* of the chio command, the ces pointer, below, is computed
* such that it lines up with the structure boundary
* corresponding to the SCSI version.
*/
ces = cmd == OCHIOGSTATUS ?
(struct changer_element_status *)
((unsigned char *)user_data + i *
(offsetof(struct changer_element_status,ces_scsi_lun)+1)):
&user_data[i];
copy_element_status(softc, pg_hdr->flags, desc,
ces, scsi_version);
desc = (struct read_element_status_descriptor *)
((uintptr_t)desc + desclen);
((unsigned char *)desc + desclen);
}
/* Copy element status structures out to userspace. */
error = copyout(user_data,
cesr->cesr_element_status,
avail * sizeof(struct changer_element_status));
if (cmd == OCHIOGSTATUS)
error = copyout(user_data,
cesr->cesr_element_status,
avail* (offsetof(struct changer_element_status,
ces_scsi_lun) + 1));
else
error = copyout(user_data,
cesr->cesr_element_status,
avail * sizeof(struct changer_element_status));
cam_periph_lock(periph);
done:
@ -1549,6 +1662,39 @@ chgetparams(struct cam_periph *periph)
return(error);
}
static int
chscsiversion(struct cam_periph *periph)
{
struct scsi_inquiry_data *inq_data;
struct ccb_getdev *cgd;
int dev_scsi_version;
struct cam_sim *sim;
sim = xpt_path_sim(periph->path);
mtx_assert(sim->mtx, MA_OWNED);
if ((cgd = (struct ccb_getdev *)xpt_alloc_ccb_nowait()) == NULL)
return (-1);
/*
* Get the device information.
*/
xpt_setup_ccb(&cgd->ccb_h,
periph->path,
CAM_PRIORITY_NORMAL);
cgd->ccb_h.func_code = XPT_GDEV_TYPE;
xpt_action((union ccb *)cgd);
if (cgd->ccb_h.status != CAM_REQ_CMP) {
xpt_free_ccb((union ccb *)cgd);
return -1;
}
inq_data = &cgd->inq_data;
dev_scsi_version = inq_data->version;
xpt_free_ccb((union ccb *)cgd);
return dev_scsi_version;
}
void
scsi_move_medium(struct ccb_scsiio *csio, u_int32_t retries,
void (*cbfcnp)(struct cam_periph *, union ccb *),
@ -1654,6 +1800,7 @@ 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,
int curdata, int dvcid,
u_int32_t count, u_int8_t *data_ptr,
u_int32_t dxfer_len, u_int8_t sense_len,
u_int32_t timeout)
@ -1668,6 +1815,10 @@ scsi_read_element_status(struct ccb_scsiio *csio, u_int32_t retries,
scsi_ulto2b(sea, scsi_cmd->sea);
scsi_ulto2b(count, scsi_cmd->count);
scsi_ulto3b(dxfer_len, scsi_cmd->len);
if (dvcid)
scsi_cmd->flags |= READ_ELEMENT_STATUS_DVCID;
if (curdata)
scsi_cmd->flags |= READ_ELEMENT_STATUS_CURDATA;
if (voltag)
scsi_cmd->byte2 |= READ_ELEMENT_STATUS_VOLTAG;

View File

@ -136,11 +136,14 @@ struct scsi_position_to_element {
struct scsi_read_element_status {
u_int8_t opcode;
u_int8_t byte2;
#define READ_ELEMENT_STATUS_VOLTAG 0x10 /* report volume tag info */
#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 flags;
#define READ_ELEMENT_STATUS_DVCID 0x01 /* report device serial number */
#define READ_ELEMENT_STATUS_CURDATA 0x02 /* allow motion during command */
u_int8_t len[3]; /* length of data buffer */
u_int8_t reserved1;
u_int8_t control;
@ -149,7 +152,7 @@ struct scsi_read_element_status {
struct scsi_request_volume_element_address {
u_int8_t opcode;
u_int8_t byte2;
#define REQUEST_VOLUME_ELEMENT_ADDRESS_VOLTAG 0x10
#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 */
@ -182,8 +185,8 @@ struct read_element_status_header {
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
#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 */
@ -199,50 +202,79 @@ struct volume_tag {
u_int8_t vsn[2]; /* volume sequence number */
};
struct read_element_status_device_id {
u_int8_t prot_code_set;
#define READ_ELEMENT_STATUS_CODE_SET(p) ((p) & 0x0F)
#define READ_ELEMENT_STATUS_PROTOCOL_ID(p) ((p) >> 4)
u_int8_t piv_assoc_designator_type;
#define READ_ELEMENT_STATUS_PIV_SET 0x80
#define READ_ELEMENT_STATUS_ASSOCIATION(p) ((p) >> 4)
#define READ_ELEMENT_STATUS_DESIGNATOR_TYPE(p) ((p) & 0x0F)
u_int8_t reserved2;
u_int8_t designator_length;
u_int8_t designator[256]; /* Allocate max length */
};
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_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
#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;
union {
struct {
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
#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 dt_scsi_addr;
u_int8_t reserved1;
} scsi_2;
u_int8_t reserved1;
/* reserved and obsolete (as of SCSI-3) fields */
u_int8_t reserved_or_obsolete[3];
} dt_or_obsolete;
u_int8_t flags2;
#define READ_ELEMENT_STATUS_INVERT 0x40
#define READ_ELEMENT_STATUS_SVALID 0x80
#define READ_ELEMENT_STATUS_INVERT 0x40
#define READ_ELEMENT_STATUS_SVALID 0x80
#define READ_ELEMENT_STATUS_ED 0x80
#define READ_ELEMENT_STATUS_MEDIA_TYPE_MASK 0x07
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 */
union {
struct volume_tag pvoltag;
struct volume_tag voltag[2];
struct read_element_status_device_id devid;
struct {
struct volume_tag pvoltag;
struct read_element_status_device_id devid;
} pvol_and_devid;
struct {
struct volume_tag voltag[2];
struct read_element_status_device_id devid;
} vol_tags_and_devid;
} voltag_devid;
};
/* XXX add data returned by REQUEST VOLUME ELEMENT ADDRESS */
@ -457,6 +489,7 @@ void scsi_position_to_element(struct ccb_scsiio *csio, u_int32_t retries,
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,
int curdata, int dvcid,
u_int32_t count, u_int8_t *data_ptr,
u_int32_t dxfer_len, u_int8_t sense_len,
u_int32_t timeout);

View File

@ -152,7 +152,8 @@ typedef enum {
CES_INVERT = 0x040, /* invert bit */
CES_SOURCE_VALID = 0x080, /* source address (ces_source) valid */
CES_SCSIID_VALID = 0x100, /* ces_scsi_id is valid */
CES_LUN_VALID = 0x200 /* ces_scsi_lun is valid */
CES_LUN_VALID = 0x200, /* ces_scsi_lun is valid */
CES_PIV = 0x400 /* ces_protocol_id is valid */
} ces_status_flags;
struct changer_element_status {
@ -181,6 +182,55 @@ struct changer_element_status {
changer_voltag_t ces_avoltag; /* alternate volume tag */
u_int8_t ces_scsi_id; /* SCSI id of element */
u_int8_t ces_scsi_lun; /* SCSI lun of element */
/*
* Data members for SMC3 and later versions
*/
u_int8_t ces_medium_type;
#define CES_MEDIUM_TYPE_UNKNOWN 0 /* Medium type unspecified */
#define CES_MEDIUM_TYPE_DATA 1 /* Data medium */
#define CES_MEDIUM_TYPE_CLEANING 2 /* Cleaning medium */
#define CES_MEDIUM_TYPE_DIAGNOSTIC 3 /* Diagnostic medium */
#define CES_MEDIUM_TYPE_WORM 4 /* WORM medium */
#define CES_MEDIUM_TYPE_MICROCODE 5 /* Microcode image medium */
u_int8_t ces_protocol_id;
#define CES_PROTOCOL_ID_FCP_4 0 /* Fiber channel */
#define CES_PROTOCOL_ID_SPI_5 1 /* Parallel SCSI */
#define CES_PROTOCOL_ID_SSA_S3P 2 /* SSA */
#define CES_PROTOCOL_ID_SBP_3 3 /* IEEE 1394 */
#define CES_PROTOCOL_ID_SRP 4 /* SCSI Remote DMA */
#define CES_PROTOCOL_ID_ISCSI 5 /* iSCSI */
#define CES_PROTOCOL_ID_SPL 6 /* SAS */
#define CES_PROTOCOL_ID_ADT_2 7 /* Automation/Drive Interface */
#define CES_PROTOCOL_ID_ACS_2 8 /* ATA */
u_int8_t ces_assoc;
#define CES_ASSOC_LOGICAL_UNIT 0
#define CES_ASSOC_TARGET_PORT 1
#define CES_ASSOC_TARGET_DEVICE 2
u_int8_t ces_designator_type;
#define CES_DESIGNATOR_TYPE_VENDOR_SPECIFIC 0
#define CES_DESIGNATOR_TYPE_T10_VENDOR_ID 1
#define CES_DESIGNATOR_TYPE_EUI_64 2
#define CES_DESIGNATOR_TYPE_NAA 3
#define CES_DESIGNATOR_TYPE_TARGET_PORT_ID 4
#define CES_DESIGNATOR_TYPE_TARGET_PORT_GRP 5
#define CES_DESIGNATOR_TYPE_LOGICAL_UNIT_GRP 6
#define CES_DESIGNATOR_TYPE_MD5_LOGICAL_UNIT_ID 7
#define CES_DESIGNATOR_TYPE_SCSI_NAME_STRING 8
u_int8_t ces_code_set;
#define CES_CODE_SET_RESERVED 0
#define CES_CODE_SET_BINARY 1
#define CES_CODE_SET_ASCII 2
#define CES_CODE_SET_UTF_8 3
u_int8_t ces_designator_length;
#define CES_MAX_DESIGNATOR_LENGTH (1 << 8)
u_int8_t ces_designator[CES_MAX_DESIGNATOR_LENGTH + 1];
};
struct changer_element_status_request {
@ -189,7 +239,7 @@ struct changer_element_status_request {
u_int16_t cesr_element_count;
u_int16_t cesr_flags;
#define CESR_VOLTAGS 0x01
#define CESR_VOLTAGS 0x01
struct changer_element_status *cesr_element_status;
};
@ -200,28 +250,29 @@ struct changer_set_voltag_request {
u_int16_t csvr_addr;
u_int16_t csvr_flags;
#define CSVR_MODE_MASK 0x0f /* mode mask, acceptable modes below: */
#define CSVR_MODE_MASK 0x0f /* mode mask, acceptable modes below: */
#define CSVR_MODE_SET 0x00 /* set volume tag if not set */
#define CSVR_MODE_REPLACE 0x01 /* unconditionally replace volume tag */
#define CSVR_MODE_CLEAR 0x02 /* clear volume tag */
#define CSVR_MODE_REPLACE 0x01 /* unconditionally replace volume tag */
#define CSVR_MODE_CLEAR 0x02 /* clear volume tag */
#define CSVR_ALTERNATE 0x10 /* set to work with alternate voltag */
#define CSVR_ALTERNATE 0x10 /* set to work with alternate voltag */
changer_voltag_t csvr_voltag;
};
#define CESTATUS_BITS \
#define CESTATUS_BITS \
"\20\6INEAB\5EXENAB\4ACCESS\3EXCEPT\2IMPEXP\1FULL"
#define CHIOMOVE _IOW('c', 0x01, struct changer_move)
#define CHIOEXCHANGE _IOW('c', 0x02, struct changer_exchange)
#define CHIOPOSITION _IOW('c', 0x03, struct changer_position)
#define CHIOGPICKER _IOR('c', 0x04, int)
#define CHIOSPICKER _IOW('c', 0x05, int)
#define CHIOGPARAMS _IOR('c', 0x06, struct changer_params)
#define CHIOIELEM _IOW('c', 0x07, u_int32_t)
#define CHIOGSTATUS _IOW('c', 0x08, struct changer_element_status_request)
#define CHIOSETVOLTAG _IOW('c', 0x09, struct changer_set_voltag_request)
#define CHIOMOVE _IOW('c', 0x01, struct changer_move)
#define CHIOEXCHANGE _IOW('c', 0x02, struct changer_exchange)
#define CHIOPOSITION _IOW('c', 0x03, struct changer_position)
#define CHIOGPICKER _IOR('c', 0x04, int)
#define CHIOSPICKER _IOW('c', 0x05, int)
#define CHIOGPARAMS _IOR('c', 0x06, struct changer_params)
#define CHIOIELEM _IOW('c', 0x07, u_int32_t)
#define OCHIOGSTATUS _IOW('c', 0x08, struct changer_element_status_request)
#define CHIOSETVOLTAG _IOW('c', 0x09, struct changer_set_voltag_request)
#define CHIOGSTATUS _IOW('c', 0x0A, struct changer_element_status_request)
#endif /* !_SYS_CHIO_H_ */