118c2aff7Sartem /*************************************************************************** 218c2aff7Sartem * 3e6996a4dSartem * cdutils.c : CD/DVD utilities 418c2aff7Sartem * 5e6996a4dSartem * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 618c2aff7Sartem * Use is subject to license terms. 718c2aff7Sartem * 818c2aff7Sartem * Licensed under the Academic Free License version 2.1 918c2aff7Sartem * 1018c2aff7Sartem **************************************************************************/ 1118c2aff7Sartem 1218c2aff7Sartem #pragma ident "%Z%%M% %I% %E% SMI" 1318c2aff7Sartem 1418c2aff7Sartem #ifdef HAVE_CONFIG_H 1518c2aff7Sartem # include <config.h> 1618c2aff7Sartem #endif 1718c2aff7Sartem 1818c2aff7Sartem #include <stdio.h> 1918c2aff7Sartem #include <sys/types.h> 2018c2aff7Sartem #include <sys/scsi/impl/uscsi.h> 2118c2aff7Sartem #include <string.h> 2218c2aff7Sartem #include <strings.h> 2318c2aff7Sartem #include <unistd.h> 2418c2aff7Sartem #include <stdlib.h> 2518c2aff7Sartem #include <errno.h> 2618c2aff7Sartem #include <fcntl.h> 2718c2aff7Sartem #include <sys/dkio.h> 2818c2aff7Sartem #include <libintl.h> 2918c2aff7Sartem 3018c2aff7Sartem #include <logger.h> 3118c2aff7Sartem 3218c2aff7Sartem #include "cdutils.h" 3318c2aff7Sartem 3418c2aff7Sartem #define RQLEN 32 3518c2aff7Sartem #define SENSE_KEY(rqbuf) (rqbuf[2]) /* scsi error category */ 3618c2aff7Sartem #define ASC(rqbuf) (rqbuf[12]) /* additional sense code */ 3718c2aff7Sartem #define ASCQ(rqbuf) (rqbuf[13]) /* ASC qualifier */ 3818c2aff7Sartem 3918c2aff7Sartem #define GET16(a) (((a)[0] << 8) | (a)[1]) 4018c2aff7Sartem #define GET32(a) (((a)[0] << 24) | ((a)[1] << 16) | ((a)[2] << 8) | (a)[3]) 4118c2aff7Sartem 4218c2aff7Sartem #define CD_USCSI_TIMEOUT 60 4318c2aff7Sartem 4418c2aff7Sartem void 4518c2aff7Sartem uscsi_cmd_init(struct uscsi_cmd *scmd, char *cdb, int cdblen) 4618c2aff7Sartem { 4718c2aff7Sartem bzero(scmd, sizeof (*scmd)); 4818c2aff7Sartem bzero(cdb, cdblen); 4918c2aff7Sartem scmd->uscsi_cdb = cdb; 5018c2aff7Sartem } 5118c2aff7Sartem 5218c2aff7Sartem int 5318c2aff7Sartem uscsi(int fd, struct uscsi_cmd *scmd) 5418c2aff7Sartem { 5518c2aff7Sartem char rqbuf[RQLEN]; 5618c2aff7Sartem int ret; 5718c2aff7Sartem int i, retries, total_retries; 5818c2aff7Sartem int max_retries = 20; 5918c2aff7Sartem 6018c2aff7Sartem scmd->uscsi_flags |= USCSI_RQENABLE; 6118c2aff7Sartem scmd->uscsi_rqlen = RQLEN; 6218c2aff7Sartem scmd->uscsi_rqbuf = rqbuf; 6318c2aff7Sartem 6418c2aff7Sartem for (retries = 0; retries < max_retries; retries++) { 6518c2aff7Sartem scmd->uscsi_status = 0; 6618c2aff7Sartem memset(rqbuf, 0, RQLEN); 6718c2aff7Sartem 6818c2aff7Sartem ret = ioctl(fd, USCSICMD, scmd); 6918c2aff7Sartem 7018c2aff7Sartem if ((ret == 0) && (scmd->uscsi_status == 2)) { 7118c2aff7Sartem ret = -1; 7218c2aff7Sartem errno = EIO; 7318c2aff7Sartem } 7418c2aff7Sartem if ((ret < 0) && (scmd->uscsi_status == 2)) { 7518c2aff7Sartem /* 7618c2aff7Sartem * The drive is not ready to recieve commands but 7718c2aff7Sartem * may be in the process of becoming ready. 7818c2aff7Sartem * sleep for a short time then retry command. 7918c2aff7Sartem * SENSE/ASC = 2/4 : not ready 8018c2aff7Sartem * ASCQ = 0 Not Reportable. 8118c2aff7Sartem * ASCQ = 1 Becoming ready. 8218c2aff7Sartem * ASCQ = 4 FORMAT in progress. 8318c2aff7Sartem * ASCQ = 7 Operation in progress. 8418c2aff7Sartem */ 8518c2aff7Sartem if ((SENSE_KEY(rqbuf) == 2) && (ASC(rqbuf) == 4) && 8618c2aff7Sartem ((ASCQ(rqbuf) == 0) || (ASCQ(rqbuf) == 1) || 8718c2aff7Sartem (ASCQ(rqbuf) == 4)) || (ASCQ(rqbuf) == 7)) { 8818c2aff7Sartem total_retries++; 8918c2aff7Sartem sleep(1); 9018c2aff7Sartem continue; 9118c2aff7Sartem } 9218c2aff7Sartem 9318c2aff7Sartem /* 9418c2aff7Sartem * Device is not ready to transmit or a device reset 9518c2aff7Sartem * has occurred. wait for a short period of time then 9618c2aff7Sartem * retry the command. 9718c2aff7Sartem */ 9818c2aff7Sartem if ((SENSE_KEY(rqbuf) == 6) && ((ASC(rqbuf) == 0x28) || 9918c2aff7Sartem (ASC(rqbuf) == 0x29))) { 10018c2aff7Sartem sleep(1); 10118c2aff7Sartem total_retries++; 10218c2aff7Sartem continue; 10318c2aff7Sartem } 10418c2aff7Sartem /* 10518c2aff7Sartem * Blank Sense, we don't know what the error is or if 10618c2aff7Sartem * the command succeeded, Hope for the best. Some 10718c2aff7Sartem * drives return blank sense periodically and will 10818c2aff7Sartem * fail if this is removed. 10918c2aff7Sartem */ 11018c2aff7Sartem if ((SENSE_KEY(rqbuf) == 0) && (ASC(rqbuf) == 0) && 11118c2aff7Sartem (ASCQ(rqbuf) == 0)) { 11218c2aff7Sartem ret = 0; 11318c2aff7Sartem break; 11418c2aff7Sartem } 11518c2aff7Sartem 11618c2aff7Sartem HAL_DEBUG (("cmd: 0x%02x ret:%i status:%02x " 11718c2aff7Sartem " sense: %02x ASC: %02x ASCQ:%02x\n", 11818c2aff7Sartem (uchar_t)scmd->uscsi_cdb[0], ret, 11918c2aff7Sartem scmd->uscsi_status, 12018c2aff7Sartem (uchar_t)SENSE_KEY(rqbuf), 12118c2aff7Sartem (uchar_t)ASC(rqbuf), (uchar_t)ASCQ(rqbuf))); 12218c2aff7Sartem } 12318c2aff7Sartem 12418c2aff7Sartem break; 12518c2aff7Sartem } 12618c2aff7Sartem 12718c2aff7Sartem if (retries) { 12818c2aff7Sartem HAL_DEBUG (("total retries: %d\n", total_retries)); 12918c2aff7Sartem } 13018c2aff7Sartem 13118c2aff7Sartem return (ret); 13218c2aff7Sartem } 13318c2aff7Sartem 13418c2aff7Sartem int 13518c2aff7Sartem mode_sense(int fd, uchar_t pc, int dbd, int page_len, uchar_t *buffer) 13618c2aff7Sartem { 13718c2aff7Sartem struct uscsi_cmd scmd; 13818c2aff7Sartem char cdb[16]; 13918c2aff7Sartem 14018c2aff7Sartem uscsi_cmd_init(&scmd, cdb, sizeof (cdb)); 14118c2aff7Sartem scmd.uscsi_flags = USCSI_READ|USCSI_SILENT; 14218c2aff7Sartem scmd.uscsi_buflen = page_len; 14318c2aff7Sartem scmd.uscsi_bufaddr = (char *)buffer; 14418c2aff7Sartem scmd.uscsi_timeout = CD_USCSI_TIMEOUT; 14518c2aff7Sartem scmd.uscsi_cdblen = 0xa; 14618c2aff7Sartem scmd.uscsi_cdb[0] = 0x5a; /* MODE SENSE 10 */ 14718c2aff7Sartem if (dbd) { 14818c2aff7Sartem scmd.uscsi_cdb[1] = 0x8; /* no block descriptors */ 14918c2aff7Sartem } 15018c2aff7Sartem scmd.uscsi_cdb[2] = pc; 15118c2aff7Sartem scmd.uscsi_cdb[7] = (page_len >> 8) & 0xff; 15218c2aff7Sartem scmd.uscsi_cdb[8] = page_len & 0xff; 15318c2aff7Sartem 15418c2aff7Sartem return (uscsi(fd, &scmd) == 0); 15518c2aff7Sartem } 15618c2aff7Sartem 15718c2aff7Sartem /* 15818c2aff7Sartem * will get the mode page only i.e. will strip off the header. 15918c2aff7Sartem */ 16018c2aff7Sartem int 16118c2aff7Sartem get_mode_page(int fd, int page_no, int pc, int buf_len, uchar_t *buffer, int *plen) 16218c2aff7Sartem { 16318c2aff7Sartem int ret; 16418c2aff7Sartem uchar_t byte2; 16518c2aff7Sartem uchar_t buf[256]; 16618c2aff7Sartem uint_t header_len, page_len, copy_cnt; 16718c2aff7Sartem 16818c2aff7Sartem byte2 = (uchar_t)(((pc << 6) & 0xC0) | (page_no & 0x3f)); 16918c2aff7Sartem 17018c2aff7Sartem /* Ask 254 bytes only to make our IDE driver happy */ 17118c2aff7Sartem if ((ret = mode_sense(fd, byte2, 1, 254, buf)) == 0) { 17218c2aff7Sartem return (0); 17318c2aff7Sartem } 17418c2aff7Sartem 17518c2aff7Sartem header_len = 8 + GET16(&buf[6]); 17618c2aff7Sartem page_len = buf[header_len + 1] + 2; 17718c2aff7Sartem 17818c2aff7Sartem copy_cnt = (page_len > buf_len) ? buf_len : page_len; 17918c2aff7Sartem (void) memcpy(buffer, &buf[header_len], copy_cnt); 18018c2aff7Sartem 18118c2aff7Sartem if (plen) { 18218c2aff7Sartem *plen = page_len; 18318c2aff7Sartem } 18418c2aff7Sartem 18518c2aff7Sartem return (1); 18618c2aff7Sartem } 18718c2aff7Sartem 18818c2aff7Sartem /* Get information about the Logical Unit's capabilities */ 18918c2aff7Sartem int 19018c2aff7Sartem get_configuration(int fd, uint16_t feature, int bufsize, uchar_t *buf) 19118c2aff7Sartem { 19218c2aff7Sartem struct uscsi_cmd scmd; 19318c2aff7Sartem char cdb[16]; 19418c2aff7Sartem 19518c2aff7Sartem uscsi_cmd_init(&scmd, cdb, sizeof (cdb)); 19618c2aff7Sartem scmd.uscsi_flags = USCSI_READ|USCSI_SILENT; 19718c2aff7Sartem scmd.uscsi_timeout = CD_USCSI_TIMEOUT; 19818c2aff7Sartem scmd.uscsi_cdb[0] = 0x46; /* GET CONFIGURATION */ 19918c2aff7Sartem scmd.uscsi_cdb[1] = 0x2; /* request type */ 20018c2aff7Sartem scmd.uscsi_cdb[2] = (feature >> 8) & 0xff; /* starting feature # */ 20118c2aff7Sartem scmd.uscsi_cdb[3] = feature & 0xff; 20218c2aff7Sartem scmd.uscsi_cdb[7] = (bufsize >> 8) & 0xff; /* allocation length */ 20318c2aff7Sartem scmd.uscsi_cdb[8] = bufsize & 0xff; 20418c2aff7Sartem scmd.uscsi_cdblen = 10; 20518c2aff7Sartem scmd.uscsi_bufaddr = (char *)buf; 20618c2aff7Sartem scmd.uscsi_buflen = bufsize; 20718c2aff7Sartem 20818c2aff7Sartem return (uscsi(fd, &scmd) == 0); 20918c2aff7Sartem } 21018c2aff7Sartem 21118c2aff7Sartem boolean_t 21218c2aff7Sartem get_current_profile(int fd, int *profile) 21318c2aff7Sartem { 21418c2aff7Sartem size_t i; 21518c2aff7Sartem uchar_t smallbuf[4]; 21618c2aff7Sartem size_t buflen; 21718c2aff7Sartem uchar_t *bufp; 21818c2aff7Sartem int ret = B_FALSE; 21918c2aff7Sartem 22018c2aff7Sartem /* first determine amount of memory needed to hold all profiles */ 22118c2aff7Sartem if (get_configuration(fd, 0, 4, &smallbuf[0])) { 22218c2aff7Sartem buflen = GET32(smallbuf) + 4; 22318c2aff7Sartem bufp = (uchar_t *)malloc(buflen); 22418c2aff7Sartem 22518c2aff7Sartem /* now get all profiles */ 22618c2aff7Sartem if (get_configuration(fd, 0, buflen, bufp)) { 22718c2aff7Sartem *profile = GET16(&bufp[6]); 22818c2aff7Sartem ret = B_TRUE; 22918c2aff7Sartem } 23018c2aff7Sartem free(bufp); 23118c2aff7Sartem } 23218c2aff7Sartem 23318c2aff7Sartem return (ret); 23418c2aff7Sartem } 23518c2aff7Sartem 23618c2aff7Sartem void 23718c2aff7Sartem walk_profiles(int fd, int (*f)(void *, int, boolean_t), void *arg) 23818c2aff7Sartem { 23918c2aff7Sartem size_t i; 24018c2aff7Sartem uint16_t profile, current_profile; 24118c2aff7Sartem uchar_t smallbuf[4]; 24218c2aff7Sartem size_t buflen; 24318c2aff7Sartem uchar_t *bufp; 24418c2aff7Sartem int ret; 24518c2aff7Sartem 24618c2aff7Sartem /* first determine amount of memory needed to hold all profiles */ 24718c2aff7Sartem if (get_configuration(fd, 0, 4, &smallbuf[0])) { 24818c2aff7Sartem buflen = GET32(smallbuf) + 4; 24918c2aff7Sartem bufp = (uchar_t *)malloc(buflen); 25018c2aff7Sartem 25118c2aff7Sartem /* now get all profiles */ 25218c2aff7Sartem if (get_configuration(fd, 0, buflen, bufp)) { 25318c2aff7Sartem current_profile = GET16(&bufp[6]); 25418c2aff7Sartem for (i = 8 + 4; i < buflen; i += 4) { 25518c2aff7Sartem profile = GET16(&bufp[i]); 25618c2aff7Sartem ret = f(arg, profile, (profile == current_profile)); 25718c2aff7Sartem if (ret == CDUTIL_WALK_STOP) { 25818c2aff7Sartem break; 25918c2aff7Sartem } 26018c2aff7Sartem } 26118c2aff7Sartem } 26218c2aff7Sartem 26318c2aff7Sartem free(bufp); 26418c2aff7Sartem } 26518c2aff7Sartem } 26618c2aff7Sartem 26718c2aff7Sartem /* retrieve speed list from the Write Speed Performance Descriptor Blocks 26818c2aff7Sartem */ 26918c2aff7Sartem void 27018c2aff7Sartem get_write_speeds(uchar_t *page, int n, intlist_t **speeds, int *n_speeds, intlist_t **speeds_mem) 27118c2aff7Sartem { 27218c2aff7Sartem uchar_t *p = page + 2; 27318c2aff7Sartem int i; 27418c2aff7Sartem intlist_t **nextp; 27518c2aff7Sartem intlist_t *current; 27618c2aff7Sartem boolean_t skip; 27718c2aff7Sartem 27818c2aff7Sartem *n_speeds = 0; 27918c2aff7Sartem *speeds = NULL; 28018c2aff7Sartem *speeds_mem = (intlist_t *)calloc(n, sizeof (intlist_t)); 28118c2aff7Sartem if (*speeds_mem == NULL) { 28218c2aff7Sartem return; 28318c2aff7Sartem } 28418c2aff7Sartem 28518c2aff7Sartem for (i = 0; i < n; i++, p += 4) { 28618c2aff7Sartem current = &(*speeds_mem)[i]; 28718c2aff7Sartem current->val = GET16(p); 28818c2aff7Sartem 28918c2aff7Sartem /* keep the list sorted */ 29018c2aff7Sartem skip = B_FALSE; 29118c2aff7Sartem for (nextp = speeds; *nextp != NULL; nextp = &((*nextp)->next)) { 29218c2aff7Sartem if (current->val == (*nextp)->val) { 29318c2aff7Sartem skip = B_TRUE; /* skip duplicates */ 29418c2aff7Sartem break; 29518c2aff7Sartem } else if (current->val > (*nextp)->val) { 29618c2aff7Sartem break; 29718c2aff7Sartem } 29818c2aff7Sartem } 29918c2aff7Sartem if (!skip) { 30018c2aff7Sartem current->next = *nextp; 30118c2aff7Sartem *nextp = current; 30218c2aff7Sartem *n_speeds++; 30318c2aff7Sartem } 30418c2aff7Sartem } 30518c2aff7Sartem } 30618c2aff7Sartem 30718c2aff7Sartem void 30818c2aff7Sartem get_read_write_speeds(int fd, int *read_speed, int *write_speed, 30918c2aff7Sartem intlist_t **speeds, int *n_speeds, intlist_t **speeds_mem) 31018c2aff7Sartem { 31118c2aff7Sartem int page_len; 31218c2aff7Sartem uchar_t p[254]; 31318c2aff7Sartem int n; /* number of write speed performance descriptor blocks */ 31418c2aff7Sartem 31518c2aff7Sartem *read_speed = *write_speed = 0; 31618c2aff7Sartem *speeds = *speeds_mem = NULL; 31718c2aff7Sartem 31818c2aff7Sartem if (!get_mode_page(fd, 0x2A, 0, sizeof (p), p, &page_len)) { 31918c2aff7Sartem return; 32018c2aff7Sartem } 32118c2aff7Sartem 32218c2aff7Sartem if (page_len > 8) { 32318c2aff7Sartem *read_speed = GET16(&p[8]); 32418c2aff7Sartem } 32518c2aff7Sartem if (page_len > 18) { 32618c2aff7Sartem *write_speed = GET16(&p[18]); 32718c2aff7Sartem } 32818c2aff7Sartem if (page_len < 28) { 32918c2aff7Sartem printf("MMC-2\n"); 33018c2aff7Sartem return; 33118c2aff7Sartem } else { 33218c2aff7Sartem printf("MMC-3\n"); 33318c2aff7Sartem } 33418c2aff7Sartem 33518c2aff7Sartem *write_speed = GET16(&p[28]); 33618c2aff7Sartem 33718c2aff7Sartem if (page_len < 30) { 33818c2aff7Sartem return; 33918c2aff7Sartem } 34018c2aff7Sartem 34118c2aff7Sartem /* retrieve speed list */ 34218c2aff7Sartem n = GET16(&p[30]); 34318c2aff7Sartem n = min(n, (sizeof (p) - 32) / 4); 34418c2aff7Sartem 34518c2aff7Sartem get_write_speeds(&p[32], n, speeds, n_speeds, speeds_mem); 34618c2aff7Sartem 34718c2aff7Sartem if (*speeds != NULL) { 34818c2aff7Sartem *write_speed = max(*write_speed, (*speeds)[0].val); 34918c2aff7Sartem } 35018c2aff7Sartem } 35118c2aff7Sartem 35218c2aff7Sartem boolean_t 35318c2aff7Sartem get_disc_info(int fd, disc_info_t *di) 35418c2aff7Sartem { 35518c2aff7Sartem struct uscsi_cmd scmd; 35618c2aff7Sartem char cdb[16]; 35718c2aff7Sartem uint8_t buf[32]; 35818c2aff7Sartem int bufsize = sizeof (buf); 35918c2aff7Sartem 36018c2aff7Sartem bzero(buf, bufsize); 36118c2aff7Sartem uscsi_cmd_init(&scmd, cdb, sizeof (cdb)); 36218c2aff7Sartem scmd.uscsi_flags = USCSI_READ|USCSI_SILENT; 36318c2aff7Sartem scmd.uscsi_timeout = CD_USCSI_TIMEOUT; 36418c2aff7Sartem scmd.uscsi_cdb[0] = 0x51; /* READ DISC INFORMATION */ 36518c2aff7Sartem scmd.uscsi_cdb[7] = (bufsize >> 8) & 0xff; /* allocation length */ 36618c2aff7Sartem scmd.uscsi_cdb[8] = bufsize & 0xff; 36718c2aff7Sartem scmd.uscsi_cdblen = 10; 36818c2aff7Sartem scmd.uscsi_bufaddr = (char *)buf; 36918c2aff7Sartem scmd.uscsi_buflen = bufsize; 37018c2aff7Sartem 37118c2aff7Sartem if ((uscsi(fd, &scmd)) != 0) { 37218c2aff7Sartem return (B_FALSE); 37318c2aff7Sartem } 37418c2aff7Sartem 375e6996a4dSartem /* 376e6996a4dSartem * According to MMC-5 6.22.3.2, the Disc Information Length should be 377e6996a4dSartem * 32+8*(Number of OPC Tables). Some devices, like U3 sticks, return 0. 378*771e4261Sartem * Yet some drives can return less than 32. We only need the first 22. 379e6996a4dSartem */ 380*771e4261Sartem if (GET16(&buf[0]) < 22) { 381e6996a4dSartem return (B_FALSE); 382e6996a4dSartem } 383e6996a4dSartem 38418c2aff7Sartem di->disc_status = buf[2] & 0x03; 38518c2aff7Sartem di->erasable = buf[2] & 0x10; 38618c2aff7Sartem if ((buf[21] != 0) && (buf[21] != 0xff)) { 38718c2aff7Sartem di->capacity = ((buf[21] * 60) + buf[22]) * 75; 38818c2aff7Sartem } else { 38918c2aff7Sartem di->capacity = 0; 39018c2aff7Sartem } 39118c2aff7Sartem 39218c2aff7Sartem return (B_TRUE); 39318c2aff7Sartem } 39418c2aff7Sartem 39518c2aff7Sartem /* 39618c2aff7Sartem * returns current/maximum format capacity in bytes 39718c2aff7Sartem */ 39818c2aff7Sartem boolean_t 39918c2aff7Sartem read_format_capacity(int fd, uint64_t *capacity) 40018c2aff7Sartem { 40118c2aff7Sartem struct uscsi_cmd scmd; 40218c2aff7Sartem char cdb[16]; 40318c2aff7Sartem uint8_t buf[32]; 40418c2aff7Sartem int bufsize = sizeof (buf); 40518c2aff7Sartem uint32_t num_blocks; 40618c2aff7Sartem uint32_t block_len; 40718c2aff7Sartem 40818c2aff7Sartem bzero(buf, bufsize); 40918c2aff7Sartem uscsi_cmd_init(&scmd, cdb, sizeof (cdb)); 41018c2aff7Sartem scmd.uscsi_flags = USCSI_READ|USCSI_SILENT; 41118c2aff7Sartem scmd.uscsi_timeout = CD_USCSI_TIMEOUT; 41218c2aff7Sartem scmd.uscsi_cdb[0] = 0x23; /* READ FORMAT CAPACITIRES */ 41318c2aff7Sartem scmd.uscsi_cdb[7] = (bufsize >> 8) & 0xff; /* allocation length */ 41418c2aff7Sartem scmd.uscsi_cdb[8] = bufsize & 0xff; 41518c2aff7Sartem scmd.uscsi_cdblen = 12; 41618c2aff7Sartem scmd.uscsi_bufaddr = (char *)buf; 41718c2aff7Sartem scmd.uscsi_buflen = bufsize; 41818c2aff7Sartem 41918c2aff7Sartem if ((uscsi(fd, &scmd)) != 0) { 42018c2aff7Sartem return (B_FALSE); 42118c2aff7Sartem } 42218c2aff7Sartem 42318c2aff7Sartem num_blocks = (uint32_t)(buf[4] << 24) + (buf[5] << 16) + (buf[6] << 8) + buf[7]; 42418c2aff7Sartem block_len = (uint32_t)(buf[9] << 16) + (buf[10] << 8) + buf[11]; 42518c2aff7Sartem *capacity = (uint64_t)num_blocks * block_len; 42618c2aff7Sartem 42718c2aff7Sartem return (B_TRUE); 42818c2aff7Sartem } 42918c2aff7Sartem 43018c2aff7Sartem boolean_t 43118c2aff7Sartem get_media_info(int fd, struct dk_minfo *minfop) 43218c2aff7Sartem { 43318c2aff7Sartem return (ioctl(fd, DKIOCGMEDIAINFO, minfop) != -1); 43418c2aff7Sartem } 43518c2aff7Sartem 43618c2aff7Sartem /* 43718c2aff7Sartem * given current profile, use the best method for determining 43818c2aff7Sartem * disc capacity (in bytes) 43918c2aff7Sartem */ 44018c2aff7Sartem boolean_t 44118c2aff7Sartem get_disc_capacity_for_profile(int fd, int profile, uint64_t *capacity) 44218c2aff7Sartem { 44318c2aff7Sartem struct dk_minfo mi; 44418c2aff7Sartem disc_info_t di; 44518c2aff7Sartem boolean_t ret = B_FALSE; 44618c2aff7Sartem 44718c2aff7Sartem switch (profile) { 44818c2aff7Sartem case 0x08: /* CD-ROM */ 44918c2aff7Sartem case 0x10: /* DVD-ROM */ 45018c2aff7Sartem if (get_media_info(fd, &mi) && (mi.dki_capacity > 1)) { 45118c2aff7Sartem *capacity = mi.dki_capacity * mi.dki_lbsize; 45218c2aff7Sartem ret = B_TRUE; 45318c2aff7Sartem } 45418c2aff7Sartem break; 45518c2aff7Sartem default: 45618c2aff7Sartem if (read_format_capacity(fd, capacity) && (*capacity > 0)) { 45718c2aff7Sartem ret = B_TRUE; 45818c2aff7Sartem } else if (get_disc_info(fd, &di) && (di.capacity > 0)) { 45918c2aff7Sartem if (get_media_info(fd, &mi)) { 46018c2aff7Sartem *capacity = di.capacity * mi.dki_lbsize; 46118c2aff7Sartem ret = B_TRUE; 46218c2aff7Sartem } 46318c2aff7Sartem } 46418c2aff7Sartem } 46518c2aff7Sartem 46618c2aff7Sartem return (ret); 46718c2aff7Sartem } 46818c2aff7Sartem 46918c2aff7Sartem boolean_t 47018c2aff7Sartem read_toc(int fd, int format, int trackno, int buflen, uchar_t *buf) 47118c2aff7Sartem { 47218c2aff7Sartem struct uscsi_cmd scmd; 47318c2aff7Sartem char cdb[16]; 47418c2aff7Sartem 47518c2aff7Sartem bzero(buf, buflen); 47618c2aff7Sartem uscsi_cmd_init(&scmd, cdb, sizeof (cdb)); 47718c2aff7Sartem scmd.uscsi_flags = USCSI_READ|USCSI_SILENT; 47818c2aff7Sartem scmd.uscsi_timeout = CD_USCSI_TIMEOUT; 47918c2aff7Sartem scmd.uscsi_cdb[0] = 0x43 /* READ_TOC_CMD */; 48018c2aff7Sartem scmd.uscsi_cdb[2] = format & 0xf; 48118c2aff7Sartem scmd.uscsi_cdb[6] = trackno; 48218c2aff7Sartem scmd.uscsi_cdb[8] = buflen & 0xff; 48318c2aff7Sartem scmd.uscsi_cdb[7] = (buflen >> 8) & 0xff; 48418c2aff7Sartem scmd.uscsi_cdblen = 10; 48518c2aff7Sartem scmd.uscsi_bufaddr = (char *)buf; 48618c2aff7Sartem scmd.uscsi_buflen = buflen; 48718c2aff7Sartem 48818c2aff7Sartem if ((uscsi(fd, &scmd)) != 0) { 48918c2aff7Sartem return (B_FALSE); 49018c2aff7Sartem } 49118c2aff7Sartem 49218c2aff7Sartem return (B_TRUE); 49318c2aff7Sartem } 494