From d8f1e148f1ff3e728a8030d0cec846f97305f5d7 Mon Sep 17 00:00:00 2001 From: ken Date: Fri, 12 May 2000 03:36:02 +0000 Subject: Add support for the DVD ioctl interface. --- sys/cam/scsi/scsi_cd.c | 587 ++++++++++++++++++++++++++++++++++++++++++++++++- sys/cam/scsi/scsi_cd.h | 497 +++++++++++++++++++++++++++++++++++++++++ sys/sys/dvdio.h | 2 + 3 files changed, 1085 insertions(+), 1 deletion(-) (limited to 'sys') diff --git a/sys/cam/scsi/scsi_cd.c b/sys/cam/scsi/scsi_cd.c index 3bd9437..4f23117 100644 --- a/sys/cam/scsi/scsi_cd.c +++ b/sys/cam/scsi/scsi_cd.c @@ -1,6 +1,6 @@ /* * Copyright (c) 1997 Justin T. Gibbs. - * Copyright (c) 1997, 1998, 1999 Kenneth D. Merry. + * Copyright (c) 1997, 1998, 1999, 2000 Kenneth D. Merry. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -56,6 +56,7 @@ #include #include #include +#include #include #include @@ -226,6 +227,12 @@ static int cdplaytracks(struct cam_periph *periph, static int cdpause(struct cam_periph *periph, u_int32_t go); static int cdstopunit(struct cam_periph *periph, u_int32_t eject); static int cdstartunit(struct cam_periph *periph); +static int cdreportkey(struct cam_periph *periph, + struct dvd_authinfo *authinfo); +static int cdsendkey(struct cam_periph *periph, + struct dvd_authinfo *authinfo); +static int cdreaddvdstructure(struct cam_periph *periph, + struct dvd_struct *dvdstruct); static struct periph_driver cddriver = { @@ -2399,6 +2406,27 @@ cdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) /* return (cd_reset(periph)); */ error = ENOTTY; break; + case DVDIOCSENDKEY: + case DVDIOCREPORTKEY: { + struct dvd_authinfo *authinfo; + + authinfo = (struct dvd_authinfo *)addr; + + if (cmd == DVDIOCREPORTKEY) + error = cdreportkey(periph, authinfo); + else + error = cdsendkey(periph, authinfo); + break; + } + case DVDIOCREADSTRUCTURE: { + struct dvd_struct *dvdstruct; + + dvdstruct = (struct dvd_struct *)addr; + + error = cdreaddvdstructure(periph, dvdstruct); + + break; + } default: error = cam_periph_ioctl(periph, cmd, addr, cderror); break; @@ -2941,3 +2969,560 @@ cdstopunit(struct cam_periph *periph, u_int32_t eject) return(error); } + +static int +cdreportkey(struct cam_periph *periph, struct dvd_authinfo *authinfo) +{ + union ccb *ccb; + u_int8_t *databuf; + u_int32_t lba; + int error; + int length; + + error = 0; + databuf = NULL; + lba = 0; + + ccb = cdgetccb(periph, /* priority */ 1); + + switch (authinfo->format) { + case DVD_REPORT_AGID: + length = sizeof(struct scsi_report_key_data_agid); + break; + case DVD_REPORT_CHALLENGE: + length = sizeof(struct scsi_report_key_data_challenge); + break; + case DVD_REPORT_KEY1: + length = sizeof(struct scsi_report_key_data_key1_key2); + break; + case DVD_REPORT_TITLE_KEY: + length = sizeof(struct scsi_report_key_data_title); + /* The lba field is only set for the title key */ + lba = authinfo->lba; + break; + case DVD_REPORT_ASF: + length = sizeof(struct scsi_report_key_data_asf); + break; + case DVD_REPORT_RPC: + length = sizeof(struct scsi_report_key_data_rpc); + break; + case DVD_INVALIDATE_AGID: + length = 0; + break; + default: + error = EINVAL; + goto bailout; + break; /* NOTREACHED */ + } + + if (length != 0) { + databuf = malloc(length, M_DEVBUF, M_WAITOK); + bzero(databuf, length); + } else + databuf = NULL; + + + scsi_report_key(&ccb->csio, + /* retries */ 1, + /* cbfcnp */ cddone, + /* tag_action */ MSG_SIMPLE_Q_TAG, + /* lba */ lba, + /* agid */ authinfo->agid, + /* key_format */ authinfo->format, + /* data_ptr */ databuf, + /* dxfer_len */ length, + /* sense_len */ SSD_FULL_SIZE, + /* timeout */ 50000); + + error = cdrunccb(ccb, cderror, /*cam_flags*/0, + /*sense_flags*/SF_RETRY_UA | SF_RETRY_SELTO); + + if (error != 0) + goto bailout; + + if (ccb->csio.resid != 0) { + xpt_print_path(periph->path); + printf("warning, residual for report key command is %d\n", + ccb->csio.resid); + } + + switch(authinfo->format) { + case DVD_REPORT_AGID: { + struct scsi_report_key_data_agid *agid_data; + + agid_data = (struct scsi_report_key_data_agid *)databuf; + + authinfo->agid = (agid_data->agid & RKD_AGID_MASK) >> + RKD_AGID_SHIFT; + break; + } + case DVD_REPORT_CHALLENGE: { + struct scsi_report_key_data_challenge *chal_data; + + chal_data = (struct scsi_report_key_data_challenge *)databuf; + + bcopy(chal_data->challenge_key, authinfo->keychal, + min(sizeof(chal_data->challenge_key), + sizeof(authinfo->keychal))); + break; + } + case DVD_REPORT_KEY1: { + struct scsi_report_key_data_key1_key2 *key1_data; + + key1_data = (struct scsi_report_key_data_key1_key2 *)databuf; + + bcopy(key1_data->key1, authinfo->keychal, + min(sizeof(key1_data->key1), sizeof(authinfo->keychal))); + break; + } + case DVD_REPORT_TITLE_KEY: { + struct scsi_report_key_data_title *title_data; + + title_data = (struct scsi_report_key_data_title *)databuf; + + authinfo->cpm = (title_data->byte0 & RKD_TITLE_CPM) >> + RKD_TITLE_CPM_SHIFT; + authinfo->cp_sec = (title_data->byte0 & RKD_TITLE_CP_SEC) >> + RKD_TITLE_CP_SEC_SHIFT; + authinfo->cgms = (title_data->byte0 & RKD_TITLE_CMGS_MASK) >> + RKD_TITLE_CMGS_SHIFT; + bcopy(title_data->title_key, authinfo->keychal, + min(sizeof(title_data->title_key), + sizeof(authinfo->keychal))); + break; + } + case DVD_REPORT_ASF: { + struct scsi_report_key_data_asf *asf_data; + + asf_data = (struct scsi_report_key_data_asf *)databuf; + + authinfo->asf = asf_data->success & RKD_ASF_SUCCESS; + break; + } + case DVD_REPORT_RPC: { + struct scsi_report_key_data_rpc *rpc_data; + + rpc_data = (struct scsi_report_key_data_rpc *)databuf; + + authinfo->reg_type = (rpc_data->byte4 & RKD_RPC_TYPE_MASK) >> + RKD_RPC_TYPE_SHIFT; + authinfo->vend_rsts = + (rpc_data->byte4 & RKD_RPC_VENDOR_RESET_MASK) >> + RKD_RPC_VENDOR_RESET_SHIFT; + authinfo->user_rsts = rpc_data->byte4 & RKD_RPC_USER_RESET_MASK; + break; + } + case DVD_INVALIDATE_AGID: + break; + default: + /* This should be impossible, since we checked above */ + error = EINVAL; + goto bailout; + break; /* NOTREACHED */ + } +bailout: + if (databuf != NULL) + free(databuf, M_DEVBUF); + + xpt_release_ccb(ccb); + + return(error); +} + +static int +cdsendkey(struct cam_periph *periph, struct dvd_authinfo *authinfo) +{ + union ccb *ccb; + u_int8_t *databuf; + int length; + int error; + + error = 0; + databuf = NULL; + + ccb = cdgetccb(periph, /* priority */ 1); + + switch(authinfo->format) { + case DVD_SEND_CHALLENGE: { + struct scsi_report_key_data_challenge *challenge_data; + + length = sizeof(*challenge_data); + + challenge_data = malloc(length, M_DEVBUF, M_WAITOK); + + databuf = (u_int8_t *)challenge_data; + + bzero(databuf, length); + + scsi_ulto2b(length - sizeof(challenge_data->data_len), + challenge_data->data_len); + + bcopy(authinfo->keychal, challenge_data->challenge_key, + min(sizeof(authinfo->keychal), + sizeof(challenge_data->challenge_key))); + break; + } + case DVD_SEND_KEY2: { + struct scsi_report_key_data_key1_key2 *key2_data; + + length = sizeof(*key2_data); + + key2_data = malloc(length, M_DEVBUF, M_WAITOK); + + databuf = (u_int8_t *)key2_data; + + bzero(databuf, length); + + scsi_ulto2b(length - sizeof(key2_data->data_len), + key2_data->data_len); + + bcopy(authinfo->keychal, key2_data->key1, + min(sizeof(authinfo->keychal), sizeof(key2_data->key1))); + + break; + } + case DVD_SEND_RPC: { + struct scsi_send_key_data_rpc *rpc_data; + + length = sizeof(*rpc_data); + + rpc_data = malloc(length, M_DEVBUF, M_WAITOK); + + databuf = (u_int8_t *)rpc_data; + + bzero(databuf, length); + + scsi_ulto2b(length - sizeof(rpc_data->data_len), + rpc_data->data_len); + + /* + * XXX KDM is this the right field from authinfo to use? + */ + rpc_data->region_code = authinfo->region; + break; + } + default: + error = EINVAL; + goto bailout; + break; /* NOTREACHED */ + } + + scsi_send_key(&ccb->csio, + /* retries */ 1, + /* cbfcnp */ cddone, + /* tag_action */ MSG_SIMPLE_Q_TAG, + /* agid */ authinfo->agid, + /* key_format */ authinfo->format, + /* data_ptr */ databuf, + /* dxfer_len */ length, + /* sense_len */ SSD_FULL_SIZE, + /* timeout */ 50000); + + error = cdrunccb(ccb, cderror, /*cam_flags*/0, + /*sense_flags*/SF_RETRY_UA | SF_RETRY_SELTO); + +bailout: + + if (databuf != NULL) + free(databuf, M_DEVBUF); + + xpt_release_ccb(ccb); + + return(error); +} + +static int +cdreaddvdstructure(struct cam_periph *periph, struct dvd_struct *dvdstruct) +{ + union ccb *ccb; + u_int8_t *databuf; + u_int32_t address; + int error; + int length; + + error = 0; + databuf = NULL; + /* The address is reserved for many of the formats */ + address = 0; + + ccb = cdgetccb(periph, /* priority */ 1); + + switch(dvdstruct->format) { + case DVD_STRUCT_PHYSICAL: + length = sizeof(struct scsi_read_dvd_struct_data_physical); + break; + case DVD_STRUCT_COPYRIGHT: + length = sizeof(struct scsi_read_dvd_struct_data_copyright); + break; + case DVD_STRUCT_DISCKEY: + length = sizeof(struct scsi_read_dvd_struct_data_disc_key); + break; + case DVD_STRUCT_BCA: + length = sizeof(struct scsi_read_dvd_struct_data_bca); + break; + case DVD_STRUCT_MANUFACT: + length = sizeof(struct scsi_read_dvd_struct_data_manufacturer); + break; + case DVD_STRUCT_CMI: + error = ENODEV; + goto bailout; +#ifdef notyet + length = sizeof(struct scsi_read_dvd_struct_data_copy_manage); + address = dvdstruct->address; +#endif + break; /* NOTREACHED */ + case DVD_STRUCT_PROTDISCID: + length = sizeof(struct scsi_read_dvd_struct_data_prot_discid); + break; + case DVD_STRUCT_DISCKEYBLOCK: + length = sizeof(struct scsi_read_dvd_struct_data_disc_key_blk); + break; + case DVD_STRUCT_DDS: + length = sizeof(struct scsi_read_dvd_struct_data_dds); + break; + case DVD_STRUCT_MEDIUM_STAT: + length = sizeof(struct scsi_read_dvd_struct_data_medium_status); + break; + case DVD_STRUCT_SPARE_AREA: + length = sizeof(struct scsi_read_dvd_struct_data_spare_area); + break; + case DVD_STRUCT_RMD_LAST: + error = ENODEV; + goto bailout; +#ifdef notyet + length = sizeof(struct scsi_read_dvd_struct_data_rmd_borderout); + address = dvdstruct->address; +#endif + break; /* NOTREACHED */ + case DVD_STRUCT_RMD_RMA: + error = ENODEV; + goto bailout; +#ifdef notyet + length = sizeof(struct scsi_read_dvd_struct_data_rmd); + address = dvdstruct->address; +#endif + break; /* NOTREACHED */ + case DVD_STRUCT_PRERECORDED: + length = sizeof(struct scsi_read_dvd_struct_data_leadin); + break; + case DVD_STRUCT_UNIQUEID: + length = sizeof(struct scsi_read_dvd_struct_data_disc_id); + break; + case DVD_STRUCT_DCB: + error = ENODEV; + goto bailout; +#ifdef notyet + length = sizeof(struct scsi_read_dvd_struct_data_dcb); + address = dvdstruct->address; +#endif + break; /* NOTREACHED */ + case DVD_STRUCT_LIST: + /* + * This is the maximum allocation length for the READ DVD + * STRUCTURE command. There's nothing in the MMC3 spec + * that indicates a limit in the amount of data that can + * be returned from this call, other than the limits + * imposed by the 2-byte length variables. + */ + length = 65535; + break; + default: + error = EINVAL; + goto bailout; + break; /* NOTREACHED */ + } + + if (length != 0) { + databuf = malloc(length, M_DEVBUF, M_WAITOK); + bzero(databuf, length); + } else + databuf = NULL; + + scsi_read_dvd_structure(&ccb->csio, + /* retries */ 1, + /* cbfcnp */ cddone, + /* tag_action */ MSG_SIMPLE_Q_TAG, + /* lba */ address, + /* layer_number */ dvdstruct->layer_num, + /* key_format */ dvdstruct->format, + /* agid */ dvdstruct->agid, + /* data_ptr */ databuf, + /* dxfer_len */ length, + /* sense_len */ SSD_FULL_SIZE, + /* timeout */ 50000); + + error = cdrunccb(ccb, cderror, /*cam_flags*/0, + /*sense_flags*/SF_RETRY_UA | SF_RETRY_SELTO); + + if (error != 0) + goto bailout; + + switch(dvdstruct->format) { + case DVD_STRUCT_PHYSICAL: { + struct scsi_read_dvd_struct_data_layer_desc *inlayer; + struct dvd_layer *outlayer; + struct scsi_read_dvd_struct_data_physical *phys_data; + + phys_data = + (struct scsi_read_dvd_struct_data_physical *)databuf; + inlayer = &phys_data->layer_desc; + outlayer = (struct dvd_layer *)&dvdstruct->data; + + dvdstruct->length = sizeof(*inlayer); + + outlayer->book_type = (inlayer->book_type_version & + RDSD_BOOK_TYPE_MASK) >> RDSD_BOOK_TYPE_SHIFT; + outlayer->book_version = (inlayer->book_type_version & + RDSD_BOOK_VERSION_MASK); + outlayer->disc_size = (inlayer->disc_size_max_rate & + RDSD_DISC_SIZE_MASK) >> RDSD_DISC_SIZE_SHIFT; + outlayer->max_rate = (inlayer->disc_size_max_rate & + RDSD_MAX_RATE_MASK); + outlayer->nlayers = (inlayer->layer_info & + RDSD_NUM_LAYERS_MASK) >> RDSD_NUM_LAYERS_SHIFT; + outlayer->track_path = (inlayer->layer_info & + RDSD_TRACK_PATH_MASK) >> RDSD_TRACK_PATH_SHIFT; + outlayer->layer_type = (inlayer->layer_info & + RDSD_LAYER_TYPE_MASK); + outlayer->linear_density = (inlayer->density & + RDSD_LIN_DENSITY_MASK) >> RDSD_LIN_DENSITY_SHIFT; + outlayer->track_density = (inlayer->density & + RDSD_TRACK_DENSITY_MASK); + outlayer->bca = (inlayer->bca & RDSD_BCA_MASK) >> + RDSD_BCA_SHIFT; + outlayer->start_sector = scsi_3btoul(inlayer->main_data_start); + outlayer->end_sector = scsi_3btoul(inlayer->main_data_end); + outlayer->end_sector_l0 = + scsi_3btoul(inlayer->end_sector_layer0); + break; + } + case DVD_STRUCT_COPYRIGHT: { + struct scsi_read_dvd_struct_data_copyright *copy_data; + + copy_data = (struct scsi_read_dvd_struct_data_copyright *) + databuf; + + dvdstruct->cpst = copy_data->cps_type; + dvdstruct->rmi = copy_data->region_info; + dvdstruct->length = 0; + + break; + } + default: + /* + * Tell the user what the overall length is, no matter + * what we can actually fit in the data buffer. + */ + dvdstruct->length = length - ccb->csio.resid - + sizeof(struct scsi_read_dvd_struct_data_header); + + /* + * But only actually copy out the smaller of what we read + * in or what the structure can take. + */ + bcopy(databuf + sizeof(struct scsi_read_dvd_struct_data_header), + dvdstruct->data, + min(sizeof(dvdstruct->data), dvdstruct->length)); + break; + } +bailout: + + if (databuf != NULL) + free(databuf, M_DEVBUF); + + xpt_release_ccb(ccb); + + return(error); +} + +void +scsi_report_key(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, u_int32_t lba, u_int8_t agid, + u_int8_t key_format, u_int8_t *data_ptr, u_int32_t dxfer_len, + u_int8_t sense_len, u_int32_t timeout) +{ + struct scsi_report_key *scsi_cmd; + + scsi_cmd = (struct scsi_report_key *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = REPORT_KEY; + scsi_ulto4b(lba, scsi_cmd->lba); + scsi_ulto2b(dxfer_len, scsi_cmd->alloc_len); + scsi_cmd->agid_keyformat = (agid << RK_KF_AGID_SHIFT) | + (key_format & RK_KF_KEYFORMAT_MASK); + + cam_fill_csio(csio, + retries, + cbfcnp, + /*flags*/ (dxfer_len == 0) ? CAM_DIR_NONE : CAM_DIR_IN, + tag_action, + /*data_ptr*/ data_ptr, + /*dxfer_len*/ dxfer_len, + sense_len, + sizeof(*scsi_cmd), + timeout); +} + +void +scsi_send_key(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, u_int8_t agid, u_int8_t key_format, + u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len, + u_int32_t timeout) +{ + struct scsi_send_key *scsi_cmd; + + scsi_cmd = (struct scsi_send_key *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = SEND_KEY; + + scsi_ulto2b(dxfer_len, scsi_cmd->param_len); + scsi_cmd->agid_keyformat = (agid << RK_KF_AGID_SHIFT) | + (key_format & RK_KF_KEYFORMAT_MASK); + + cam_fill_csio(csio, + retries, + cbfcnp, + /*flags*/ CAM_DIR_OUT, + tag_action, + /*data_ptr*/ data_ptr, + /*dxfer_len*/ dxfer_len, + sense_len, + sizeof(*scsi_cmd), + timeout); +} + + +void +scsi_read_dvd_structure(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, u_int32_t address, + u_int8_t layer_number, u_int8_t format, u_int8_t agid, + u_int8_t *data_ptr, u_int32_t dxfer_len, + u_int8_t sense_len, u_int32_t timeout) +{ + struct scsi_read_dvd_structure *scsi_cmd; + + scsi_cmd = (struct scsi_read_dvd_structure *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = READ_DVD_STRUCTURE; + + scsi_ulto4b(address, scsi_cmd->address); + scsi_cmd->layer_number = layer_number; + scsi_cmd->format = format; + scsi_ulto2b(dxfer_len, scsi_cmd->alloc_len); + /* The AGID is the top two bits of this byte */ + scsi_cmd->agid = agid << 6; + + cam_fill_csio(csio, + retries, + cbfcnp, + /*flags*/ CAM_DIR_IN, + tag_action, + /*data_ptr*/ data_ptr, + /*dxfer_len*/ dxfer_len, + sense_len, + sizeof(*scsi_cmd), + timeout); +} diff --git a/sys/cam/scsi/scsi_cd.h b/sys/cam/scsi/scsi_cd.h index 284c710..b055202 100644 --- a/sys/cam/scsi/scsi_cd.h +++ b/sys/cam/scsi/scsi_cd.h @@ -1,3 +1,29 @@ +/*- + * Copyright (c) 2000 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. + * + */ /* * Written by Julian Elischer (julian@tfs.com) * for TRW Financial Systems. @@ -144,6 +170,71 @@ struct scsi_read_cd_capacity u_int8_t control; }; +struct scsi_report_key +{ + u_int8_t opcode; + u_int8_t reserved0; + u_int8_t lba[4]; + u_int8_t reserved1[2]; + u_int8_t alloc_len[2]; + u_int8_t agid_keyformat; +#define RK_KF_AGID_MASK 0xc0 +#define RK_KF_AGID_SHIFT 6 +#define RK_KF_KEYFORMAT_MASK 0x3f +#define RK_KF_AGID 0x00 +#define RK_KF_CHALLENGE 0x01 +#define RF_KF_KEY1 0x02 +#define RK_KF_KEY2 0x03 +#define RF_KF_TITLE 0x04 +#define RF_KF_ASF 0x05 +#define RK_KF_RPC_SET 0x06 +#define RF_KF_RPC_REPORT 0x08 +#define RF_KF_INV_AGID 0x3f + u_int8_t control; +}; + +/* + * See the report key structure for key format and AGID definitions. + */ +struct scsi_send_key +{ + u_int8_t opcode; + u_int8_t reserved[7]; + u_int8_t param_len[2]; + u_int8_t agid_keyformat; + u_int8_t control; +}; + +struct scsi_read_dvd_structure +{ + u_int8_t opcode; + u_int8_t reserved; + u_int8_t address[4]; + u_int8_t layer_number; + u_int8_t format; +#define RDS_FORMAT_PHYSICAL 0x00 +#define RDS_FORMAT_COPYRIGHT 0x01 +#define RDS_FORMAT_DISC_KEY 0x02 +#define RDS_FORMAT_BCA 0x03 +#define RDS_FORMAT_MANUFACTURER 0x04 +#define RDS_FORMAT_CMGS_CPM 0x05 +#define RDS_FORMAT_PROT_DISCID 0x06 +#define RDS_FORMAT_DISC_KEY_BLOCK 0x07 +#define RDS_FORMAT_DDS 0x08 +#define RDS_FORMAT_DVDRAM_MEDIA_STAT 0x09 +#define RDS_FORMAT_SPARE_AREA 0x0a +#define RDS_FORMAT_RMD_BORDEROUT 0x0c +#define RDS_FORMAT_RMD 0x0d +#define RDS_FORMAT_LEADIN 0x0e +#define RDS_FORMAT_DISC_ID 0x0f +#define RDS_FORMAT_DCB 0x30 +#define RDS_FORMAT_WRITE_PROT 0xc0 +#define RDS_FORMAT_STRUCTURE_LIST 0xff + u_int8_t alloc_len[2]; + u_int8_t agid; + u_int8_t control; +}; + /* * Opcodes */ @@ -156,10 +247,391 @@ struct scsi_read_cd_capacity #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 SEND_KEY 0xa3 /* dvd send key command */ +#define REPORT_KEY 0xa4 /* dvd report key command */ #define PLAY_12 0xa5 /* cdrom pause in 'play audio' mode */ #define PLAY_TRACK_REL_BIG 0xa9 /* cdrom play track/index mode */ +#define READ_DVD_STRUCTURE 0xad /* read dvd structure */ +struct scsi_report_key_data_header +{ + u_int8_t data_len[2]; + u_int8_t reserved[2]; +}; + +struct scsi_report_key_data_agid +{ + u_int8_t data_len[2]; + u_int8_t reserved[5]; + u_int8_t agid; +#define RKD_AGID_MASK 0xc0 +#define RKD_AGID_SHIFT 6 +}; + +struct scsi_report_key_data_challenge +{ + u_int8_t data_len[2]; + u_int8_t reserved0[2]; + u_int8_t challenge_key[10]; + u_int8_t reserved1[2]; +}; +struct scsi_report_key_data_key1_key2 +{ + u_int8_t data_len[2]; + u_int8_t reserved0[2]; + u_int8_t key1[5]; + u_int8_t reserved1[3]; +}; + +struct scsi_report_key_data_title +{ + u_int8_t data_len[2]; + u_int8_t reserved0[2]; + u_int8_t byte0; +#define RKD_TITLE_CPM 0x80 +#define RKD_TITLE_CPM_SHIFT 7 +#define RKD_TITLE_CP_SEC 0x40 +#define RKD_TITLE_CP_SEC_SHIFT 6 +#define RKD_TITLE_CMGS_MASK 0x30 +#define RKD_TITLE_CMGS_SHIFT 4 +#define RKD_TITLE_CMGS_NO_RST 0x00 +#define RKD_TITLE_CMGS_RSVD 0x10 +#define RKD_TITLE_CMGS_1_GEN 0x20 +#define RKD_TITLE_CMGS_NO_COPY 0x30 + u_int8_t title_key[5]; + u_int8_t reserved1[2]; +}; + +struct scsi_report_key_data_asf +{ + u_int8_t data_len[2]; + u_int8_t reserved[5]; + u_int8_t success; +#define RKD_ASF_SUCCESS 0x01 +}; + +struct scsi_report_key_data_rpc +{ + u_int8_t data_len[2]; + u_int8_t rpc_scheme0; +#define RKD_RPC_SCHEME_UNKNOWN 0x00 +#define RKD_RPC_SCHEME_PHASE_II 0x01 + u_int8_t reserved0; + u_int8_t byte4; +#define RKD_RPC_TYPE_MASK 0xC0 +#define RKD_RPC_TYPE_SHIFT 6 +#define RKD_RPC_TYPE_NONE 0x00 +#define RKD_RPC_TYPE_SET 0x40 +#define RKD_RPC_TYPE_LAST_CHANCE 0x80 +#define RKD_RPC_TYPE_PERM 0xC0 +#define RKD_RPC_VENDOR_RESET_MASK 0x38 +#define RKD_RPC_VENDOR_RESET_SHIFT 3 +#define RKD_RPC_USER_RESET_MASK 0x07 +#define RKD_RPC_USER_RESET_SHIFT 0 + u_int8_t region_mask; + u_int8_t rpc_scheme1; + u_int8_t reserved1; +}; + +struct scsi_send_key_data_rpc +{ + u_int8_t data_len[2]; + u_int8_t reserved0[2]; + u_int8_t region_code; + u_int8_t reserved1[3]; +}; + +/* + * Common header for the return data from the READ DVD STRUCTURE command. + */ +struct scsi_read_dvd_struct_data_header +{ + u_int8_t data_len[2]; + u_int8_t reserved[2]; +}; + +struct scsi_read_dvd_struct_data_layer_desc +{ + u_int8_t book_type_version; +#define RDSD_BOOK_TYPE_DVD_ROM 0x00 +#define RDSD_BOOK_TYPE_DVD_RAM 0x10 +#define RDSD_BOOK_TYPE_DVD_R 0x20 +#define RDSD_BOOK_TYPE_DVD_RW 0x30 +#define RDSD_BOOK_TYPE_DVD_PRW 0x90 +#define RDSD_BOOK_TYPE_MASK 0xf0 +#define RDSD_BOOK_TYPE_SHIFT 4 +#define RDSD_BOOK_VERSION_MASK 0x0f + /* + * The lower 4 bits of this field is referred to as the "minimum + * rate" field in MMC2, and the "maximum rate" field in MMC3. Ugh. + */ + u_int8_t disc_size_max_rate; +#define RDSD_DISC_SIZE_120MM 0x00 +#define RDSD_DISC_SIZE_80MM 0x10 +#define RDSD_DISC_SIZE_MASK 0xf0 +#define RDSD_DISC_SIZE_SHIFT 4 +#define RDSD_MAX_RATE_0252 0x00 +#define RDSD_MAX_RATE_0504 0x01 +#define RDSD_MAX_RATE_1008 0x02 +#define RDSD_MAX_RATE_NOT_SPEC 0x0f +#define RDSD_MAX_RATE_MASK 0x0f + u_int8_t layer_info; +#define RDSD_NUM_LAYERS_MASK 0x60 +#define RDSD_NUM_LAYERS_SHIFT 5 +#define RDSD_NL_ONE_LAYER 0x00 +#define RDSD_NL_TWO_LAYERS 0x20 +#define RDSD_TRACK_PATH_MASK 0x10 +#define RDSD_TRACK_PATH_SHIFT 4 +#define RDSD_TP_PTP 0x00 +#define RDSD_TP_OTP 0x10 +#define RDSD_LAYER_TYPE_RO 0x01 +#define RDSD_LAYER_TYPE_RECORD 0x02 +#define RDSD_LAYER_TYPE_RW 0x04 +#define RDSD_LAYER_TYPE_MASK 0x0f + u_int8_t density; +#define RDSD_LIN_DENSITY_0267 0x00 +#define RDSD_LIN_DENSITY_0293 0x10 +#define RDSD_LIN_DENSITY_0409_0435 0x20 +#define RDSD_LIN_DENSITY_0280_0291 0x40 +/* XXX MMC2 uses 0.176um/bit instead of 0.353 as in MMC3 */ +#define RDSD_LIN_DENSITY_0353 0x80 +#define RDSD_LIN_DENSITY_MASK 0xf0 +#define RDSD_LIN_DENSITY_SHIFT 4 +#define RDSD_TRACK_DENSITY_074 0x00 +#define RDSD_TRACK_DENSITY_080 0x01 +#define RDSD_TRACK_DENSITY_0615 0x02 +#define RDSD_TRACK_DENSITY_MASK 0x0f + u_int8_t zeros0; + u_int8_t main_data_start[3]; +#define RDSD_MAIN_DATA_START_DVD_RO 0x30000 +#define RDSD_MAIN_DATA_START_DVD_RW 0x31000 + u_int8_t zeros1; + u_int8_t main_data_end[3]; + u_int8_t zeros2; + u_int8_t end_sector_layer0[3]; + u_int8_t bca; +#define RDSD_BCA 0x80 +#define RDSD_BCA_MASK 0x80 +#define RDSD_BCA_SHIFT 7 + u_int8_t media_specific[2031]; +}; + +struct scsi_read_dvd_struct_data_physical +{ + u_int8_t data_len[2]; + u_int8_t reserved[2]; + struct scsi_read_dvd_struct_data_layer_desc layer_desc; +}; + +struct scsi_read_dvd_struct_data_copyright +{ + u_int8_t data_len[2]; + u_int8_t reserved0[2]; + u_int8_t cps_type; +#define RDSD_CPS_NOT_PRESENT 0x00 +#define RDSD_CPS_DATA_EXISTS 0x01 + u_int8_t region_info; + u_int8_t reserved1[2]; +}; + +struct scsi_read_dvd_struct_data_disc_key +{ + u_int8_t data_len[2]; + u_int8_t reserved[2]; + u_int8_t disc_key[2048]; +}; + +struct scsi_read_dvd_struct_data_bca +{ + u_int8_t data_len[2]; + u_int8_t reserved[2]; + u_int8_t bca_info[188]; /* XXX 12-188 bytes */ +}; + +struct scsi_read_dvd_struct_data_manufacturer +{ + u_int8_t data_len[2]; + u_int8_t reserved[2]; + u_int8_t manuf_info[2048]; +}; + +struct scsi_read_dvd_struct_data_copy_manage +{ + u_int8_t data_len[2]; + u_int8_t reserved0[2]; + u_int8_t byte4; +#define RDSD_CPM_NO_COPYRIGHT 0x00 +#define RDSD_CPM_HAS_COPYRIGHT 0x80 +#define RDSD_CPM_MASK 0x80 +#define RDSD_CMGS_COPY_ALLOWED 0x00 +#define RDSD_CMGS_ONE_COPY 0x20 +#define RDSD_CMGS_NO_COPIES 0x30 +#define RDSD_CMGS_MASK 0x30 + u_int8_t reserved1[3]; +}; + +struct scsi_read_dvd_struct_data_prot_discid +{ + u_int8_t data_len[2]; + u_int8_t reserved[2]; + u_int8_t prot_discid_data[16]; +}; + +struct scsi_read_dvd_struct_data_disc_key_blk +{ + /* + * Length is 0x6ffe == 28670 for CPRM, 0x3002 == 12990 for CSS2. + */ + u_int8_t data_len[2]; + u_int8_t reserved; + u_int8_t total_packs; + u_int8_t disc_key_pack_data[28668]; +}; +struct scsi_read_dvd_struct_data_dds +{ + u_int8_t data_len[2]; + u_int8_t reserved[2]; + u_int8_t dds_info[2048]; +}; + +struct scsi_read_dvd_struct_data_medium_status +{ + u_int8_t data_len[2]; + u_int8_t reserved0[2]; + u_int8_t byte4; +#define RDSD_MS_CARTRIDGE 0x80 +#define RDSD_MS_OUT 0x40 +#define RDSD_MS_MSWI 0x08 +#define RDSD_MS_CWP 0x04 +#define RDSD_MS_PWP 0x02 + u_int8_t disc_type_id; +#define RDSD_DT_NEED_CARTRIDGE 0x00 +#define RDSD_DT_NO_CART_NEEDED 0x01 + u_int8_t reserved1; + u_int8_t ram_swi_info; +#define RDSD_SWI_NO_BARE 0x01 +#define RDSD_SWI_UNSPEC 0xff +}; + +struct scsi_read_dvd_struct_data_spare_area +{ + u_int8_t data_len[2]; + u_int8_t reserved[2]; + u_int8_t unused_primary[4]; + u_int8_t unused_supl[4]; + u_int8_t allocated_supl[4]; +}; + +struct scsi_read_dvd_struct_data_rmd_borderout +{ + u_int8_t data_len[2]; + u_int8_t reserved[2]; + u_int8_t rmd[30720]; /* maximum is 30720 bytes */ +}; + +struct scsi_read_dvd_struct_data_rmd +{ + u_int8_t data_len[2]; + u_int8_t reserved[2]; + u_int8_t last_sector_num[4]; + u_int8_t rmd_bytes[32768]; /* This is the maximum */ +}; + +/* + * XXX KDM this is the MMC2 version of the structure. + * The variable positions have changed (in a semi-conflicting way) in the + * MMC3 spec, although the overall length of the structure is the same. + */ +struct scsi_read_dvd_struct_data_leadin +{ + u_int8_t data_len[2]; + u_int8_t reserved0[2]; + u_int8_t field_id_1; + u_int8_t app_code; + u_int8_t disc_physical_data; + u_int8_t last_addr[3]; + u_int8_t reserved1[2]; + u_int8_t field_id_2; + u_int8_t rwp; + u_int8_t rwp_wavelength; + u_int8_t optimum_write_strategy; + u_int8_t reserved2[4]; + u_int8_t field_id_3; + u_int8_t manuf_id_17_12[6]; + u_int8_t reserved3; + u_int8_t field_id_4; + u_int8_t manuf_id_11_6[6]; + u_int8_t reserved4; + u_int8_t field_id_5; + u_int8_t manuf_id_5_0[6]; + u_int8_t reserved5[25]; +}; + +struct scsi_read_dvd_struct_data_disc_id +{ + u_int8_t data_len[2]; + u_int8_t reserved[4]; + u_int8_t random_num[2]; + u_int8_t year[4]; + u_int8_t month[2]; + u_int8_t day[2]; + u_int8_t hour[2]; + u_int8_t minute[2]; + u_int8_t second[2]; +}; + +struct scsi_read_dvd_struct_data_generic_dcb +{ + u_int8_t content_desc[4]; +#define SCSI_RCB + u_int8_t unknown_desc_actions[4]; +#define RDSD_ACTION_RECORDING 0x0001 +#define RDSD_ACTION_READING 0x0002 +#define RDSD_ACTION_FORMAT 0x0004 +#define RDSD_ACTION_MODIFY_DCB 0x0008 + u_int8_t vendor_id[32]; + u_int8_t dcb_data[32728]; +}; + +struct scsi_read_dvd_struct_data_dcb +{ + u_int8_t data_len[2]; + u_int8_t reserved[2]; + struct scsi_read_dvd_struct_data_generic_dcb dcb; +}; + +struct read_dvd_struct_write_prot +{ + u_int8_t data_len[2]; + u_int8_t reserved0[2]; + u_int8_t write_prot_status; +#define RDSD_WPS_MSWI 0x08 +#define RDSD_WPS_CWP 0x04 +#define RDSD_WPS_PWP 0x02 +#define RDSD_WPS_SWPP 0x01 + u_int8_t reserved[3]; +}; + +struct read_dvd_struct_list_entry +{ + u_int8_t format_code; + u_int8_t sds_rds; +#define RDSD_SDS_NOT_WRITEABLE 0x00 +#define RDSD_SDS_WRITEABLE 0x80 +#define RDSD_SDS_MASK 0x80 +#define RDSD_RDS_NOT_READABLE 0x00 +#define RDSD_RDS_READABLE 0x40 +#define RDSD_RDS_MASK 0x40 + u_int8_t struct_len[2]; +}; + +struct read_dvd_struct_data_list +{ + u_int8_t data_len[2]; + u_int8_t reserved[2]; + struct read_dvd_struct_list_entry entries[0]; +}; struct scsi_read_cd_cap_data { @@ -213,5 +685,30 @@ struct cd_mode_data struct scsi_mode_blk_desc blk_desc; union cd_pages page; }; + +__BEGIN_DECLS +void scsi_report_key(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, u_int32_t lba, u_int8_t agid, + u_int8_t key_format, u_int8_t *data_ptr, + u_int32_t dxfer_len, u_int8_t sense_len, + u_int32_t timeout); + +void scsi_send_key(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, u_int8_t agid, u_int8_t key_format, + u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len, + u_int32_t timeout); + +void scsi_read_dvd_structure(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, u_int32_t address, + u_int8_t layer_number, u_int8_t format, + u_int8_t agid, u_int8_t *data_ptr, + u_int32_t dxfer_len, u_int8_t sense_len, + u_int32_t timeout); + +__END_DECLS + #endif /*_SCSI_SCSI_CD_H*/ diff --git a/sys/sys/dvdio.h b/sys/sys/dvdio.h index 42d7ca2..ee7a54c 100644 --- a/sys/sys/dvdio.h +++ b/sys/sys/dvdio.h @@ -82,6 +82,8 @@ struct dvd_authinfo { #define DVD_STRUCT_PROTDISCID 0x06 #define DVD_STRUCT_DISCKEYBLOCK 0x07 #define DVD_STRUCT_DDS 0x08 +#define DVD_STRUCT_MEDIUM_STAT 0x09 +#define DVD_STRUCT_SPARE_AREA 0x0A #define DVD_STRUCT_RMD_LAST 0x0C #define DVD_STRUCT_RMD_RMA 0x0D #define DVD_STRUCT_PRERECORDED 0x0E -- cgit v1.1