/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include "transport.h" #include "mmc.h" #include "util.h" #include "main.h" int uscsi_error; int test_unit_ready(int fd) { struct uscsi_cmd *scmd; scmd = get_uscsi_cmd(); scmd->uscsi_flags = USCSI_SILENT; scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT; /* give length of cdb structure */ scmd->uscsi_cdblen = 6; if ((uscsi_error = uscsi(fd, scmd)) < 0) return (0); return (1); } int inquiry(int fd, uchar_t *inq) { struct uscsi_cmd *scmd; scmd = get_uscsi_cmd(); scmd->uscsi_flags = USCSI_READ|USCSI_SILENT; scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT; scmd->uscsi_cdb[0] = INQUIRY_CMD; scmd->uscsi_cdb[4] = INQUIRY_DATA_LENGTH; scmd->uscsi_cdblen = 6; scmd->uscsi_bufaddr = (char *)inq; scmd->uscsi_buflen = INQUIRY_DATA_LENGTH; if ((uscsi_error = uscsi(fd, scmd)) < 0) return (0); return (1); } int read_capacity(int fd, uchar_t *capbuf) { struct uscsi_cmd *scmd; scmd = get_uscsi_cmd(); scmd->uscsi_flags = USCSI_READ|USCSI_SILENT; scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT; scmd->uscsi_cdb[0] = READ_CAP_CMD; scmd->uscsi_cdblen = 10; scmd->uscsi_bufaddr = (char *)capbuf; scmd->uscsi_buflen = 8; if ((uscsi_error = uscsi(fd, scmd)) < 0) return (0); return (1); } int mode_sense(int fd, uchar_t pc, int dbd, int page_len, uchar_t *buffer) { struct uscsi_cmd *scmd; scmd = get_uscsi_cmd(); scmd->uscsi_flags = USCSI_READ|USCSI_SILENT; scmd->uscsi_buflen = page_len; scmd->uscsi_bufaddr = (char *)buffer; scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT; scmd->uscsi_cdblen = 0xa; scmd->uscsi_cdb[0] = MODE_SENSE_10_CMD; if (dbd) { /* don't return any block descriptors */ scmd->uscsi_cdb[1] = 0x8; } /* the page code we want */ scmd->uscsi_cdb[2] = pc; /* allocation length */ scmd->uscsi_cdb[7] = (page_len >> 8) & 0xff; scmd->uscsi_cdb[8] = page_len & 0xff; if ((uscsi_error = uscsi(fd, scmd)) < 0) return (0); return (1); } int mode_select(int fd, int page_len, uchar_t *buffer) { struct uscsi_cmd *scmd; scmd = get_uscsi_cmd(); scmd->uscsi_flags = USCSI_WRITE|USCSI_SILENT; scmd->uscsi_buflen = page_len; scmd->uscsi_bufaddr = (char *)buffer; scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT; scmd->uscsi_cdblen = 0xa; /* mode select (10) command */ scmd->uscsi_cdb[0] = MODE_SELECT_10_CMD; scmd->uscsi_cdb[1] = 0x10; /* parameter list length */ scmd->uscsi_cdb[7] = (page_len >> 8) & 0xff; scmd->uscsi_cdb[8] = page_len & 0xff; if ((uscsi_error = uscsi(fd, scmd)) < 0) return (0); return (1); } int read_track_info(int fd, int trackno, uchar_t *ti) { struct uscsi_cmd *scmd; scmd = get_uscsi_cmd(); scmd->uscsi_flags = USCSI_READ|USCSI_SILENT; scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT; scmd->uscsi_cdb[0] = READ_TRACK_CMD; /* tell device we are giving it a track number */ scmd->uscsi_cdb[1] = 1; /* track number to read */ if (trackno == -1) if (device_type == CD_RW) { ((uchar_t *)scmd->uscsi_cdb)[5] = 0xff; } else { /* only 1 track is allowed on DVD media */ scmd->uscsi_cdb[1] = 0; ((uchar_t *)scmd->uscsi_cdb)[5] = 0; } else scmd->uscsi_cdb[5] = (uchar_t)trackno; scmd->uscsi_cdb[8] = TRACK_INFO_SIZE; scmd->uscsi_cdblen = 10; scmd->uscsi_bufaddr = (char *)ti; scmd->uscsi_buflen = TRACK_INFO_SIZE; if ((uscsi_error = uscsi(fd, scmd)) < 0) return (0); return (1); } int read_toc(int fd, int format, int trackno, int buflen, uchar_t *buf) { struct uscsi_cmd *scmd; scmd = get_uscsi_cmd(); scmd->uscsi_flags = USCSI_READ|USCSI_SILENT; scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT; scmd->uscsi_cdb[0] = READ_TOC_CMD; scmd->uscsi_cdb[2] = format & 0xf; scmd->uscsi_cdb[6] = trackno; scmd->uscsi_cdb[8] = buflen & 0xff; scmd->uscsi_cdb[7] = (buflen >> 8) & 0xff; scmd->uscsi_cdblen = 10; scmd->uscsi_bufaddr = (char *)buf; scmd->uscsi_buflen = buflen; if ((uscsi_error = uscsi(fd, scmd)) < 0) return (0); /* Fix for old SONY drives */ if ((format == 0) && (buflen == 4) && (buf[0] == 0) && (buf[1] == 2)) { uint16_t toc_size; toc_size = (((uint16_t)(buf[3] + 1)) * 8) + 2; load_scsi16(buf, toc_size); } return (1); } int read_header(int fd, uint32_t lba, uchar_t *buf) { struct uscsi_cmd *scmd; scmd = get_uscsi_cmd(); scmd->uscsi_flags = USCSI_READ|USCSI_SILENT; scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT; scmd->uscsi_cdb[0] = READ_HDR_CMD; /* Logical block address */ load_scsi32(&scmd->uscsi_cdb[2], lba); /* allocation length */ scmd->uscsi_cdb[8] = 8; scmd->uscsi_cdblen = 10; scmd->uscsi_bufaddr = (char *)buf; scmd->uscsi_buflen = 8; if ((uscsi_error = uscsi(fd, scmd)) < 0) return (0); return (1); } int read_disc_info(int fd, uchar_t *di) { struct uscsi_cmd *scmd; scmd = get_uscsi_cmd(); scmd->uscsi_flags = USCSI_READ|USCSI_SILENT; scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT; scmd->uscsi_cdb[0] = READ_INFO_CMD; scmd->uscsi_cdb[8] = DISC_INFO_BLOCK_SIZE; scmd->uscsi_cdblen = 10; scmd->uscsi_bufaddr = (char *)di; scmd->uscsi_buflen = DISC_INFO_BLOCK_SIZE; if ((uscsi_error = uscsi(fd, scmd)) < 0) return (0); return (1); } /* Get information about the Logical Unit's capabilities */ int get_configuration(int fd, uint16_t feature, int bufsize, uchar_t *buf) { struct uscsi_cmd *scmd; scmd = get_uscsi_cmd(); scmd->uscsi_flags = USCSI_READ|USCSI_SILENT; scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT; /* Set OPERATION CODE in CDB */ scmd->uscsi_cdb[0] = GET_CONFIG_CMD; /* * Set RT field in CDB, currently need at most one * Feature Descriptor */ scmd->uscsi_cdb[1] = 0x2; /* Set Starting Feature Number in CDB */ scmd->uscsi_cdb[2] = (feature >> 8) & 0xff; scmd->uscsi_cdb[3] = feature & 0xff; /* Set Allocation Length in CDB */ scmd->uscsi_cdb[7] = (bufsize >> 8) & 0xff; scmd->uscsi_cdb[8] = bufsize & 0xff; scmd->uscsi_cdblen = 10; scmd->uscsi_bufaddr = (char *)buf; scmd->uscsi_buflen = bufsize; if ((uscsi_error = uscsi(fd, scmd)) < 0) return (0); return (1); } int read10(int fd, uint32_t start_blk, uint16_t nblk, uchar_t *buf, uint32_t bufsize) { struct uscsi_cmd *scmd; scmd = get_uscsi_cmd(); scmd->uscsi_flags = USCSI_READ|USCSI_SILENT; scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT; scmd->uscsi_cdb[0] = READ_10_CMD; load_scsi32(&scmd->uscsi_cdb[2], start_blk); scmd->uscsi_cdb[8] = nblk & 0xff; scmd->uscsi_cdb[7] = (nblk >> 8) & 0xff; scmd->uscsi_cdblen = 10; scmd->uscsi_bufaddr = (char *)buf; scmd->uscsi_buflen = bufsize; if ((uscsi_error = uscsi(fd, scmd)) < 0) return (0); return (1); } int write10(int fd, uint32_t start_blk, uint16_t nblk, uchar_t *buf, uint32_t bufsize) { struct uscsi_cmd *scmd; scmd = get_uscsi_cmd(); scmd->uscsi_flags = USCSI_WRITE|USCSI_SILENT; /* * Some DVD drives take longer to write than * the standard time, since they tend to generate * the media TOC on the fly when the cache is full */ scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT * 3; scmd->uscsi_cdb[0] = WRITE_10_CMD; load_scsi32(&scmd->uscsi_cdb[2], start_blk); scmd->uscsi_cdb[8] = nblk & 0xff; scmd->uscsi_cdb[7] = (nblk >> 8) & 0xff; scmd->uscsi_cdblen = 10; scmd->uscsi_bufaddr = (char *)buf; scmd->uscsi_buflen = bufsize; if ((uscsi_error = uscsi(fd, scmd)) < 0) return (0); return (1); } int close_track(int fd, int trackno, int close_session, int immediate) { struct uscsi_cmd *scmd; scmd = get_uscsi_cmd(); scmd->uscsi_flags = USCSI_SILENT; scmd->uscsi_cdb[0] = CLOSE_TRACK_CMD; if (immediate) { scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT; scmd->uscsi_cdb[1] = 1; } else { scmd->uscsi_timeout = 240; } if ((close_session) || (device_type == DVD_PLUS) || (device_type == DVD_PLUS_W)) { /* close the session */ scmd->uscsi_cdb[2] = 2; } else { /* Close the track but leave session open */ scmd->uscsi_cdb[2] = 1; scmd->uscsi_cdb[5] = trackno & 0xff; } /* * DVD+R media are already formatted, we are using * a special case to notify that drive to close * track/session and null-fill the remaining space. */ if (device_type == DVD_PLUS) { scmd->uscsi_cdb[5] = 1; /* only 1 track */ if (close_session) { scmd->uscsi_cdb[2] = 6; /* session */ } else { scmd->uscsi_cdb[2] = 1; /* track */ } } scmd->uscsi_cdblen = 10; if ((uscsi_error = uscsi(fd, scmd)) < 0) return (0); return (1); } int blank_disc(int fd, int type, int immediate) { struct uscsi_cmd *scmd; scmd = get_uscsi_cmd(); scmd->uscsi_flags = USCSI_SILENT; if (immediate) { scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT; scmd->uscsi_cdb[1] = 0x10; } else { scmd->uscsi_timeout = 0x12c0; } ((uchar_t *)scmd->uscsi_cdb)[0] = BLANK_CMD; /* tell it to blank the last session or all of the disk */ scmd->uscsi_cdb[1] |= type & 0x07; scmd->uscsi_cdblen = 12; if ((uscsi_error = uscsi(fd, scmd)) < 0) return (0); return (1); } int read_cd(int fd, uint32_t start_blk, uint16_t nblk, uchar_t sector_type, uchar_t *buf, uint32_t bufsize) { struct uscsi_cmd *scmd; scmd = get_uscsi_cmd(); scmd->uscsi_flags = USCSI_READ|USCSI_SILENT; scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT; ((uchar_t *)scmd->uscsi_cdb)[0] = READ_CD_CMD; scmd->uscsi_cdb[1] = (sector_type & 0x7) << 2; scmd->uscsi_cdb[5] = start_blk & 0xff; scmd->uscsi_cdb[4] = (start_blk >> 8) & 0xff; scmd->uscsi_cdb[3] = (start_blk >> 16) & 0xff; scmd->uscsi_cdb[2] = (start_blk >> 24) & 0xff; scmd->uscsi_cdb[8] = nblk & 0xff; scmd->uscsi_cdb[7] = (nblk >> 8) & 0xff; scmd->uscsi_cdb[9] = 0x10; scmd->uscsi_cdblen = 12; scmd->uscsi_bufaddr = (char *)buf; scmd->uscsi_buflen = bufsize; if ((uscsi_error = uscsi(fd, scmd)) < 0) return (0); return (1); } int load_unload(int fd, int load) { struct uscsi_cmd *scmd; scmd = get_uscsi_cmd(); scmd->uscsi_flags = USCSI_SILENT; scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT; scmd->uscsi_cdb[0] = START_STOP_CMD; if (load == 0) { /* unload medium */ scmd->uscsi_cdb[4] = 2; } else { /* load medium */ scmd->uscsi_cdb[4] = 3; } scmd->uscsi_cdblen = 6; if ((uscsi_error = uscsi(fd, scmd)) < 0) return (0); return (1); } int prevent_allow_mr(int fd, int op) { struct uscsi_cmd *scmd; scmd = get_uscsi_cmd(); scmd->uscsi_flags = USCSI_SILENT; scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT; scmd->uscsi_cdb[0] = PREVENT_ALLOW_CMD; if (!op) { /* prevent */ scmd->uscsi_cdb[4] = 1; } scmd->uscsi_cdblen = 6; if ((uscsi_error = uscsi(fd, scmd)) < 0) return (0); return (1); } int set_cd_speed(int fd, uint16_t read_speed, uint16_t write_speed) { struct uscsi_cmd *scmd; scmd = get_uscsi_cmd(); scmd->uscsi_flags = USCSI_SILENT; scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT; scmd->uscsi_cdblen = 0xc; ((uchar_t *)scmd->uscsi_cdb)[0] = SET_CD_SPEED; scmd->uscsi_cdb[2] = (read_speed >> 8) & 0xff; scmd->uscsi_cdb[3] = read_speed & 0xff; scmd->uscsi_cdb[4] = (write_speed >> 8) & 0xff; scmd->uscsi_cdb[5] = write_speed & 0xff; if ((uscsi_error = uscsi(fd, scmd)) < 0) return (0); return (1); } int get_performance(int fd, int get_write_performance, uchar_t *perf) { struct uscsi_cmd *scmd; scmd = get_uscsi_cmd(); scmd->uscsi_flags = USCSI_READ|USCSI_SILENT; scmd->uscsi_buflen = GET_PERF_DATA_LEN; scmd->uscsi_bufaddr = (char *)perf; scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT; scmd->uscsi_cdblen = 0xc; ((uchar_t *)scmd->uscsi_cdb)[0] = GET_PERFORMANCE_CMD; scmd->uscsi_cdb[1] = 0x10; if (get_write_performance) scmd->uscsi_cdb[1] |= 4; scmd->uscsi_cdb[9] = 2; if ((uscsi_error = uscsi(fd, scmd)) < 0) return (0); return (1); } int set_streaming(int fd, uchar_t *buf) { struct uscsi_cmd *scmd; scmd = get_uscsi_cmd(); scmd->uscsi_flags = USCSI_WRITE|USCSI_SILENT; scmd->uscsi_buflen = SET_STREAM_DATA_LEN; scmd->uscsi_bufaddr = (char *)buf; scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT; scmd->uscsi_cdblen = 0xc; ((uchar_t *)scmd->uscsi_cdb)[0] = STREAM_CMD; scmd->uscsi_cdb[10] = SET_STREAM_DATA_LEN; if ((uscsi_error = uscsi(fd, scmd)) < 0) return (0); return (1); } int rezero_unit(int fd) { struct uscsi_cmd *scmd; scmd = get_uscsi_cmd(); scmd->uscsi_flags = USCSI_SILENT; scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT; scmd->uscsi_cdblen = 0x6; scmd->uscsi_cdb[0] = REZERO_UNIT_CMD; if ((uscsi_error = uscsi(fd, scmd)) < 0) return (0); return (1); } int start_stop(int fd, int start) { struct uscsi_cmd *scmd; scmd = get_uscsi_cmd(); scmd->uscsi_flags = USCSI_SILENT; scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT; scmd->uscsi_cdblen = 0x6; scmd->uscsi_cdb[0] = START_STOP_CMD; if (start) { scmd->uscsi_cdb[4] = 1; } if ((uscsi_error = uscsi(fd, scmd)) < 0) return (0); return (1); } int flush_cache(int fd) { struct uscsi_cmd *scmd; scmd = get_uscsi_cmd(); scmd->uscsi_flags = USCSI_SILENT; scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT; scmd->uscsi_cdblen = 10; scmd->uscsi_cdb[0] = SYNC_CACHE_CMD; if (device_type != CD_RW) { scmd->uscsi_cdb[1] = 0x2; /* Immediate */ } if ((uscsi_error = uscsi(fd, scmd)) < 0) return (0); return (1); } /* * used for DVD- to reserve the size we want to write. * This is used by the drive to generate a TOC. */ int set_reservation(int fd, ulong_t size) { struct uscsi_cmd *scmd; scmd = get_uscsi_cmd(); scmd->uscsi_flags = USCSI_READ|USCSI_SILENT; scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT; scmd->uscsi_cdb[0] = SET_RESERVATION_CMD; scmd->uscsi_cdblen = 10; scmd->uscsi_cdb[5] = (uchar_t)(size >> 24); scmd->uscsi_cdb[6] = (uchar_t)(size >> 16); scmd->uscsi_cdb[7] = (uchar_t)(size >> 8); scmd->uscsi_cdb[8] = (uchar_t)size; if ((uscsi_error = uscsi(fd, scmd)) < 0) return (0); return (1); } /* * Used for DVD+RW media to prepare the disk to write. * It will also be used for packet mode writing when * it becomes supported. */ int format_media(int fd) { struct uscsi_cmd *scmd; uchar_t buf[20]; (void) memset(buf, 0, 20); scmd = get_uscsi_cmd(); scmd->uscsi_flags = USCSI_READ|USCSI_SILENT; scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT; scmd->uscsi_cdblen = 12; scmd->uscsi_cdb[0] = READ_FORMAT_CAP_CMD; scmd->uscsi_cdb[8] = 0x14; /* buffer length */ scmd->uscsi_buflen = 20; scmd->uscsi_bufaddr = (char *)buf; if ((uscsi_error = uscsi(fd, scmd)) < 0) return (0); /* RE-use cap structure */ scmd->uscsi_flags = USCSI_WRITE|USCSI_SILENT; scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT; scmd->uscsi_cdblen = 6; scmd->uscsi_cdb[0] = FORMAT_UNIT_CMD; /* full format */ scmd->uscsi_cdb[1] = 0x11; scmd->uscsi_buflen = 12; buf[1] = 0x82; /* immediate and FOV */ buf[3] = 8; /* descriptor length */ buf[8] = 0x98; /* type = 26 DVD+RW format */ buf[10] = 0; if ((uscsi_error = uscsi(fd, scmd)) < 0) return (0); return (1); } /* * Prefered method of reading the media size. This is * the only supported method on several newer drives. */ uint32_t read_format_capacity(int fd, uint_t *bsize) { struct uscsi_cmd *scmd; uint32_t filesize; char buf[20]; scmd = get_uscsi_cmd(); scmd->uscsi_flags = USCSI_READ|USCSI_SILENT; scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT; scmd->uscsi_cdblen = 12; scmd->uscsi_cdb[0] = READ_FORMAT_CAP_CMD; scmd->uscsi_cdb[8] = 0x14; scmd->uscsi_buflen = 20; scmd->uscsi_bufaddr = buf; if ((uscsi_error = uscsi(fd, scmd)) < 0) return (0); filesize = (uint32_t)(((uchar_t)buf[4] << 24) + ((uchar_t)buf[5] << 16) + ((uchar_t)buf[6] << 8) + (uchar_t)buf[7]); *bsize = (uint16_t)(((uchar_t)buf[10] << 8) + (uchar_t)buf[11]); return (filesize); } /* * Used to reset the device. Since, sd(4D) requires a * command to be issued when resetting a device we will * issue an innocuous command. The command chosen for this * purpose is the TEST UNIT READY (TUR) command. We also do * not care about the sucess of the TUR so we will not return * a value. */ void reset_dev(int fd) { struct uscsi_cmd *scmd; /* * Since a TUR has SCSI operation code of 0, we * can make use of the fact that get_uscsi_cmd() * initializes a CDB to all zeros to generate * the TUR command. */ scmd = get_uscsi_cmd(); /* Tell sd(4D) to do a silent reset of the device. */ scmd->uscsi_flags = USCSI_SILENT | USCSI_RESET; scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT; scmd->uscsi_cdblen = 6; /* Issue the TUR command. */ uscsi_error = uscsi(fd, scmd); } /* * Function: ftr_supported * * Description: Check to see if a device supports a Feature * * Arguments: fd - file descriptor * feature - the MMC Feature for which we'd like to know * if there's support * * Return Code: 1 - Feature is supported * 0 - Feature is not supported * */ int ftr_supported(int fd, uint16_t feature) { size_t response_len; uchar_t *bufp; int ret; response_len = MMC_FTR_HDR_LEN + MMC_FTR_DSCRPTR_BASE_LEN; bufp = (uchar_t *)my_zalloc(response_len); /* * If a Feature is supported, a device will return a Feature Descriptor * for that Feature, and its Current Bit will be set. */ if (get_configuration(fd, feature, response_len, bufp) == 1) { /* * To check that a Feature Descriptor was returned, we * check to see if the Data Length field of the Feature * Header holds a value greater than four. To check if * the Current Bit is set, we check bit 1 of byte 10. */ if (read_scsi32(bufp) > 4 && bufp[10] & 1) ret = 1; else ret = 0; } else { /* get_configuration failed */ ret = 0; } free(bufp); return (ret); } /* * Function: print_profile_name * * Description: Prints a list of the Profiles the device supports * * Parameters: num - hexadecimal representation of Profile * current - 1 if the Profile is Current, otherwise 0 * abbr - 1 if printing abbreviated name, otherwise 0 */ void print_profile_name(uint16_t num, uchar_t current, uchar_t abbr) { if (abbr != 1) (void) printf(" 0x%04x: ", num); switch (num) { case 0x0000: (void) printf("No Current Profile"); break; case 0x0001: (void) printf("Non-Removable Disk"); break; case 0x0002: (void) printf("Removable Disk"); break; case 0x0003: (void) printf("Magneto-Optical Erasable"); break; case 0x0004: (void) printf("Optical Write Once"); break; case 0x0005: (void) printf("AS-MO"); break; case 0x0008: (void) printf("CD-ROM"); break; case 0x0009: (void) printf("CD-R"); break; case 0x000A: (void) printf("CD-RW"); break; case 0x0010: (void) printf("DVD-ROM"); break; case 0x0011: (void) printf("DVD-R"); if (abbr != 1) (void) printf(" Sequential Recording"); break; case 0x0012: (void) printf("DVD-RAM"); break; case 0x0013: (void) printf("DVD-RW"); if (abbr != 1) (void) printf(" Restricted Overwrite"); break; case 0x0014: (void) printf("DVD-RW"); if (abbr != 1) (void) printf(" Sequential Recording"); break; case 0x0015: (void) printf("DVD-R"); if (abbr != 1) (void) printf(" Dual Layer Sequential Recording"); else (void) printf(" DL"); break; case 0x0016: (void) printf("DVD-R"); if (abbr != 1) (void) printf(" Dual Layer Jump Recording"); else (void) printf(" DL"); break; case 0x0017: (void) printf("DVD-RW"); if (abbr != 1) (void) printf(" Dual Layer"); else (void) printf(" DL"); break; case 0x001A: (void) printf("DVD+RW"); break; case 0x001B: (void) printf("DVD+R"); break; case 0x0020: (void) printf("DDCD-ROM"); break; case 0x0021: (void) printf("DDCD-R"); break; case 0x0022: (void) printf("DDCD-RW"); break; case 0x002A: (void) printf("DVD+RW"); if (abbr != 1) (void) printf(" Dual Layer"); else (void) printf(" DL"); break; case 0x002B: (void) printf("DVD+R"); if (abbr != 1) (void) printf(" Dual Layer"); else (void) printf(" DL"); break; case 0x0040: (void) printf("BD-ROM"); break; case 0x0041: (void) printf("BD-R Sequential Recording (SRM) Profile"); break; case 0x0042: (void) printf("BD-R Random Recording (RRM) Profile"); break; case 0x0043: (void) printf("BD-RE"); break; case 0xFFFF: (void) printf("Nonstandard Profile"); break; default: break; } if (current == 1) (void) printf(" (Current Profile)"); (void) printf("\n"); } /* * Function: print_profile_list * * Description: Print a list of Profiles supported by the Logical Unit. * * Parameters: fd - file descriptor for device whose list of * profiles we wish to print */ void print_profile_list(int fd) { size_t i; size_t buflen; uint16_t current; uint16_t other; uchar_t *bufp = (uchar_t *)my_zalloc(MMC_FTR_HDR_LEN); /* * First get_configuration call is used to determine amount of memory * needed to hold all the Profiles. The first four bytes of bufp * concatenated tell us the number of bytes of memory we need but do * not take themselves into account. Therefore, add four, and * allocate that number of bytes. */ if (get_configuration(fd, MMC_FTR_PRFL_LIST, MMC_FTR_HDR_LEN, bufp)) { buflen = read_scsi32(bufp) + 4; free(bufp); bufp = (uchar_t *)my_zalloc(buflen); /* * Now get all the Profiles */ if (get_configuration(fd, MMC_FTR_PRFL_LIST, buflen, bufp)) { (void) printf("\nProfile List\n"); (void) printf("---------------------------------\n"); /* * Find out the Logical Unit's Current Profile */ current = read_scsi16(&bufp[6]); /* * Print out the Profile List and indicate which * Profile is Current */ for (i = MMC_FTR_HDR_LEN + MMC_FTR_DSCRPTR_BASE_LEN; i < buflen; i += MMC_PRFL_DSCRPTR_LEN) { other = read_scsi16(&bufp[i]); if (other == current) print_profile_name(other, 1, 0); else print_profile_name(other, 0, 0); } (void) printf("\n"); } } free(bufp); }