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