18c2aff776a775d34a4c9893a4c72e0434d68e36artem/***************************************************************************
e6996a4debb6ae502e3265067551ae19866a317aartem * cdutils.c : CD/DVD utilities
8cd4c22636ceaa8d2260f00cb5cedfd1d249fab9Xiaolin Zhang - Sun Microsystems - Beijing China * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * Use is subject to license terms.
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * Licensed under the Academic Free License version 2.1
18c2aff776a775d34a4c9893a4c72e0434d68e36artem **************************************************************************/
18c2aff776a775d34a4c9893a4c72e0434d68e36artem#define SENSE_KEY(rqbuf) (rqbuf[2]) /* scsi error category */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem#define ASC(rqbuf) (rqbuf[12]) /* additional sense code */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem#define GET32(a) (((a)[0] << 24) | ((a)[1] << 16) | ((a)[2] << 8) | (a)[3])
18c2aff776a775d34a4c9893a4c72e0434d68e36artemuscsi_cmd_init(struct uscsi_cmd *scmd, char *cdb, int cdblen)
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * The drive is not ready to recieve commands but
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * may be in the process of becoming ready.
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * sleep for a short time then retry command.
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * SENSE/ASC = 2/4 : not ready
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * ASCQ = 0 Not Reportable.
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * ASCQ = 1 Becoming ready.
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * ASCQ = 4 FORMAT in progress.
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * ASCQ = 7 Operation in progress.
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * Device is not ready to transmit or a device reset
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * has occurred. wait for a short period of time then
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * retry the command.
18c2aff776a775d34a4c9893a4c72e0434d68e36artem if ((SENSE_KEY(rqbuf) == 6) && ((ASC(rqbuf) == 0x28) ||
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * Blank Sense, we don't know what the error is or if
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * the command succeeded, Hope for the best. Some
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * drives return blank sense periodically and will
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * fail if this is removed.
18c2aff776a775d34a4c9893a4c72e0434d68e36artem " sense: %02x ASC: %02x ASCQ:%02x\n",
18c2aff776a775d34a4c9893a4c72e0434d68e36artemmode_sense(int fd, uchar_t pc, int dbd, int page_len, uchar_t *buffer)
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * will get the mode page only i.e. will strip off the header.
18c2aff776a775d34a4c9893a4c72e0434d68e36artemget_mode_page(int fd, int page_no, int pc, int buf_len, uchar_t *buffer, int *plen)
18c2aff776a775d34a4c9893a4c72e0434d68e36artem byte2 = (uchar_t)(((pc << 6) & 0xC0) | (page_no & 0x3f));
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* Ask 254 bytes only to make our IDE driver happy */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem if ((ret = mode_sense(fd, byte2, 1, 254, buf)) == 0) {
18c2aff776a775d34a4c9893a4c72e0434d68e36artem return (0);
18c2aff776a775d34a4c9893a4c72e0434d68e36artem return (1);
18c2aff776a775d34a4c9893a4c72e0434d68e36artem/* Get information about the Logical Unit's capabilities */
18c2aff776a775d34a4c9893a4c72e0434d68e36artemget_configuration(int fd, uint16_t feature, int bufsize, uchar_t *buf)
18c2aff776a775d34a4c9893a4c72e0434d68e36artem scmd.uscsi_cdb[2] = (feature >> 8) & 0xff; /* starting feature # */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem scmd.uscsi_cdb[7] = (bufsize >> 8) & 0xff; /* allocation length */
8cd4c22636ceaa8d2260f00cb5cedfd1d249fab9Xiaolin Zhang - Sun Microsystems - Beijing China uchar_t smallbuf[8];
8cd4c22636ceaa8d2260f00cb5cedfd1d249fab9Xiaolin Zhang - Sun Microsystems - Beijing China * first determine amount of memory needed to hold all profiles.
8cd4c22636ceaa8d2260f00cb5cedfd1d249fab9Xiaolin Zhang - Sun Microsystems - Beijing China * The first four bytes of smallbuf concatenated tell us the
8cd4c22636ceaa8d2260f00cb5cedfd1d249fab9Xiaolin Zhang - Sun Microsystems - Beijing China * number of bytes of memory we need but do not take themselves
8cd4c22636ceaa8d2260f00cb5cedfd1d249fab9Xiaolin Zhang - Sun Microsystems - Beijing China * into account. Therefore, add four to allocate that number
8cd4c22636ceaa8d2260f00cb5cedfd1d249fab9Xiaolin Zhang - Sun Microsystems - Beijing China * of bytes.
8cd4c22636ceaa8d2260f00cb5cedfd1d249fab9Xiaolin Zhang - Sun Microsystems - Beijing China if (get_configuration(fd, 0, 8, &smallbuf[0])) {
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* now get all profiles */
18c2aff776a775d34a4c9893a4c72e0434d68e36artemwalk_profiles(int fd, int (*f)(void *, int, boolean_t), void *arg)
8cd4c22636ceaa8d2260f00cb5cedfd1d249fab9Xiaolin Zhang - Sun Microsystems - Beijing China uchar_t smallbuf[8];
8cd4c22636ceaa8d2260f00cb5cedfd1d249fab9Xiaolin Zhang - Sun Microsystems - Beijing China * first determine amount of memory needed to hold all profiles.
8cd4c22636ceaa8d2260f00cb5cedfd1d249fab9Xiaolin Zhang - Sun Microsystems - Beijing China * The first four bytes of smallbuf concatenated tell us the
8cd4c22636ceaa8d2260f00cb5cedfd1d249fab9Xiaolin Zhang - Sun Microsystems - Beijing China * number of bytes of memory we need but do not take themselves
8cd4c22636ceaa8d2260f00cb5cedfd1d249fab9Xiaolin Zhang - Sun Microsystems - Beijing China * into account. Therefore, add four to allocate that number
8cd4c22636ceaa8d2260f00cb5cedfd1d249fab9Xiaolin Zhang - Sun Microsystems - Beijing China * of bytes.
8cd4c22636ceaa8d2260f00cb5cedfd1d249fab9Xiaolin Zhang - Sun Microsystems - Beijing China if (get_configuration(fd, 0, 8, &smallbuf[0])) {
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* now get all profiles */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem/* retrieve speed list from the Write Speed Performance Descriptor Blocks
18c2aff776a775d34a4c9893a4c72e0434d68e36artemget_write_speeds(uchar_t *page, int n, intlist_t **speeds, int *n_speeds, intlist_t **speeds_mem)
18c2aff776a775d34a4c9893a4c72e0434d68e36artem *speeds_mem = (intlist_t *)calloc(n, sizeof (intlist_t));
18c2aff776a775d34a4c9893a4c72e0434d68e36artem for (i = 0; i < n; i++, p += 4) {
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* keep the list sorted */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem for (nextp = speeds; *nextp != NULL; nextp = &((*nextp)->next)) {
18c2aff776a775d34a4c9893a4c72e0434d68e36artemget_read_write_speeds(int fd, int *read_speed, int *write_speed,
18c2aff776a775d34a4c9893a4c72e0434d68e36artem intlist_t **speeds, int *n_speeds, intlist_t **speeds_mem)
18c2aff776a775d34a4c9893a4c72e0434d68e36artem int n; /* number of write speed performance descriptor blocks */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem if (!get_mode_page(fd, 0x2A, 0, sizeof (p), p, &page_len)) {
18c2aff776a775d34a4c9893a4c72e0434d68e36artem /* retrieve speed list */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem get_write_speeds(&p[32], n, speeds, n_speeds, speeds_mem);
18c2aff776a775d34a4c9893a4c72e0434d68e36artem scmd.uscsi_cdb[7] = (bufsize >> 8) & 0xff; /* allocation length */
e6996a4debb6ae502e3265067551ae19866a317aartem * According to MMC-5 6.22.3.2, the Disc Information Length should be
e6996a4debb6ae502e3265067551ae19866a317aartem * 32+8*(Number of OPC Tables). Some devices, like U3 sticks, return 0.
771e42612b677c59c956a14fbfeebe6f0157fcc9artem * Yet some drives can return less than 32. We only need the first 22.
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * returns current/maximum format capacity in bytes
18c2aff776a775d34a4c9893a4c72e0434d68e36artem scmd.uscsi_cdb[0] = 0x23; /* READ FORMAT CAPACITIRES */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem scmd.uscsi_cdb[7] = (bufsize >> 8) & 0xff; /* allocation length */
18c2aff776a775d34a4c9893a4c72e0434d68e36artem num_blocks = (uint32_t)(buf[4] << 24) + (buf[5] << 16) + (buf[6] << 8) + buf[7];
18c2aff776a775d34a4c9893a4c72e0434d68e36artem block_len = (uint32_t)(buf[9] << 16) + (buf[10] << 8) + buf[11];
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * given current profile, use the best method for determining
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * disc capacity (in bytes)
18c2aff776a775d34a4c9893a4c72e0434d68e36artemget_disc_capacity_for_profile(int fd, int profile, uint64_t *capacity)
18c2aff776a775d34a4c9893a4c72e0434d68e36artem if (get_media_info(fd, &mi) && (mi.dki_capacity > 1)) {
18c2aff776a775d34a4c9893a4c72e0434d68e36artem if (read_format_capacity(fd, capacity) && (*capacity > 0)) {
18c2aff776a775d34a4c9893a4c72e0434d68e36artem } else if (get_disc_info(fd, &di) && (di.capacity > 0)) {