1*18c2aff7Sartem /*************************************************************************** 2*18c2aff7Sartem * 3*18c2aff7Sartem * cdutils.h : CD/DVD utilities 4*18c2aff7Sartem * 5*18c2aff7Sartem * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 6*18c2aff7Sartem * Use is subject to license terms. 7*18c2aff7Sartem * 8*18c2aff7Sartem * Licensed under the Academic Free License version 2.1 9*18c2aff7Sartem * 10*18c2aff7Sartem **************************************************************************/ 11*18c2aff7Sartem 12*18c2aff7Sartem #pragma ident "%Z%%M% %I% %E% SMI" 13*18c2aff7Sartem 14*18c2aff7Sartem #ifdef HAVE_CONFIG_H 15*18c2aff7Sartem # include <config.h> 16*18c2aff7Sartem #endif 17*18c2aff7Sartem 18*18c2aff7Sartem #include <stdio.h> 19*18c2aff7Sartem #include <sys/types.h> 20*18c2aff7Sartem #include <sys/scsi/impl/uscsi.h> 21*18c2aff7Sartem #include <string.h> 22*18c2aff7Sartem #include <strings.h> 23*18c2aff7Sartem #include <unistd.h> 24*18c2aff7Sartem #include <stdlib.h> 25*18c2aff7Sartem #include <errno.h> 26*18c2aff7Sartem #include <fcntl.h> 27*18c2aff7Sartem #include <sys/dkio.h> 28*18c2aff7Sartem #include <libintl.h> 29*18c2aff7Sartem 30*18c2aff7Sartem #include <logger.h> 31*18c2aff7Sartem 32*18c2aff7Sartem #include "cdutils.h" 33*18c2aff7Sartem 34*18c2aff7Sartem #define RQLEN 32 35*18c2aff7Sartem #define SENSE_KEY(rqbuf) (rqbuf[2]) /* scsi error category */ 36*18c2aff7Sartem #define ASC(rqbuf) (rqbuf[12]) /* additional sense code */ 37*18c2aff7Sartem #define ASCQ(rqbuf) (rqbuf[13]) /* ASC qualifier */ 38*18c2aff7Sartem 39*18c2aff7Sartem #define GET16(a) (((a)[0] << 8) | (a)[1]) 40*18c2aff7Sartem #define GET32(a) (((a)[0] << 24) | ((a)[1] << 16) | ((a)[2] << 8) | (a)[3]) 41*18c2aff7Sartem 42*18c2aff7Sartem #define CD_USCSI_TIMEOUT 60 43*18c2aff7Sartem 44*18c2aff7Sartem void 45*18c2aff7Sartem uscsi_cmd_init(struct uscsi_cmd *scmd, char *cdb, int cdblen) 46*18c2aff7Sartem { 47*18c2aff7Sartem bzero(scmd, sizeof (*scmd)); 48*18c2aff7Sartem bzero(cdb, cdblen); 49*18c2aff7Sartem scmd->uscsi_cdb = cdb; 50*18c2aff7Sartem } 51*18c2aff7Sartem 52*18c2aff7Sartem int 53*18c2aff7Sartem uscsi(int fd, struct uscsi_cmd *scmd) 54*18c2aff7Sartem { 55*18c2aff7Sartem char rqbuf[RQLEN]; 56*18c2aff7Sartem int ret; 57*18c2aff7Sartem int i, retries, total_retries; 58*18c2aff7Sartem int max_retries = 20; 59*18c2aff7Sartem 60*18c2aff7Sartem scmd->uscsi_flags |= USCSI_RQENABLE; 61*18c2aff7Sartem scmd->uscsi_rqlen = RQLEN; 62*18c2aff7Sartem scmd->uscsi_rqbuf = rqbuf; 63*18c2aff7Sartem 64*18c2aff7Sartem for (retries = 0; retries < max_retries; retries++) { 65*18c2aff7Sartem scmd->uscsi_status = 0; 66*18c2aff7Sartem memset(rqbuf, 0, RQLEN); 67*18c2aff7Sartem 68*18c2aff7Sartem ret = ioctl(fd, USCSICMD, scmd); 69*18c2aff7Sartem 70*18c2aff7Sartem if ((ret == 0) && (scmd->uscsi_status == 2)) { 71*18c2aff7Sartem ret = -1; 72*18c2aff7Sartem errno = EIO; 73*18c2aff7Sartem } 74*18c2aff7Sartem if ((ret < 0) && (scmd->uscsi_status == 2)) { 75*18c2aff7Sartem /* 76*18c2aff7Sartem * The drive is not ready to recieve commands but 77*18c2aff7Sartem * may be in the process of becoming ready. 78*18c2aff7Sartem * sleep for a short time then retry command. 79*18c2aff7Sartem * SENSE/ASC = 2/4 : not ready 80*18c2aff7Sartem * ASCQ = 0 Not Reportable. 81*18c2aff7Sartem * ASCQ = 1 Becoming ready. 82*18c2aff7Sartem * ASCQ = 4 FORMAT in progress. 83*18c2aff7Sartem * ASCQ = 7 Operation in progress. 84*18c2aff7Sartem */ 85*18c2aff7Sartem if ((SENSE_KEY(rqbuf) == 2) && (ASC(rqbuf) == 4) && 86*18c2aff7Sartem ((ASCQ(rqbuf) == 0) || (ASCQ(rqbuf) == 1) || 87*18c2aff7Sartem (ASCQ(rqbuf) == 4)) || (ASCQ(rqbuf) == 7)) { 88*18c2aff7Sartem total_retries++; 89*18c2aff7Sartem sleep(1); 90*18c2aff7Sartem continue; 91*18c2aff7Sartem } 92*18c2aff7Sartem 93*18c2aff7Sartem /* 94*18c2aff7Sartem * Device is not ready to transmit or a device reset 95*18c2aff7Sartem * has occurred. wait for a short period of time then 96*18c2aff7Sartem * retry the command. 97*18c2aff7Sartem */ 98*18c2aff7Sartem if ((SENSE_KEY(rqbuf) == 6) && ((ASC(rqbuf) == 0x28) || 99*18c2aff7Sartem (ASC(rqbuf) == 0x29))) { 100*18c2aff7Sartem sleep(1); 101*18c2aff7Sartem total_retries++; 102*18c2aff7Sartem continue; 103*18c2aff7Sartem } 104*18c2aff7Sartem /* 105*18c2aff7Sartem * Blank Sense, we don't know what the error is or if 106*18c2aff7Sartem * the command succeeded, Hope for the best. Some 107*18c2aff7Sartem * drives return blank sense periodically and will 108*18c2aff7Sartem * fail if this is removed. 109*18c2aff7Sartem */ 110*18c2aff7Sartem if ((SENSE_KEY(rqbuf) == 0) && (ASC(rqbuf) == 0) && 111*18c2aff7Sartem (ASCQ(rqbuf) == 0)) { 112*18c2aff7Sartem ret = 0; 113*18c2aff7Sartem break; 114*18c2aff7Sartem } 115*18c2aff7Sartem 116*18c2aff7Sartem HAL_DEBUG (("cmd: 0x%02x ret:%i status:%02x " 117*18c2aff7Sartem " sense: %02x ASC: %02x ASCQ:%02x\n", 118*18c2aff7Sartem (uchar_t)scmd->uscsi_cdb[0], ret, 119*18c2aff7Sartem scmd->uscsi_status, 120*18c2aff7Sartem (uchar_t)SENSE_KEY(rqbuf), 121*18c2aff7Sartem (uchar_t)ASC(rqbuf), (uchar_t)ASCQ(rqbuf))); 122*18c2aff7Sartem } 123*18c2aff7Sartem 124*18c2aff7Sartem break; 125*18c2aff7Sartem } 126*18c2aff7Sartem 127*18c2aff7Sartem if (retries) { 128*18c2aff7Sartem HAL_DEBUG (("total retries: %d\n", total_retries)); 129*18c2aff7Sartem } 130*18c2aff7Sartem 131*18c2aff7Sartem return (ret); 132*18c2aff7Sartem } 133*18c2aff7Sartem 134*18c2aff7Sartem int 135*18c2aff7Sartem mode_sense(int fd, uchar_t pc, int dbd, int page_len, uchar_t *buffer) 136*18c2aff7Sartem { 137*18c2aff7Sartem struct uscsi_cmd scmd; 138*18c2aff7Sartem char cdb[16]; 139*18c2aff7Sartem 140*18c2aff7Sartem uscsi_cmd_init(&scmd, cdb, sizeof (cdb)); 141*18c2aff7Sartem scmd.uscsi_flags = USCSI_READ|USCSI_SILENT; 142*18c2aff7Sartem scmd.uscsi_buflen = page_len; 143*18c2aff7Sartem scmd.uscsi_bufaddr = (char *)buffer; 144*18c2aff7Sartem scmd.uscsi_timeout = CD_USCSI_TIMEOUT; 145*18c2aff7Sartem scmd.uscsi_cdblen = 0xa; 146*18c2aff7Sartem scmd.uscsi_cdb[0] = 0x5a; /* MODE SENSE 10 */ 147*18c2aff7Sartem if (dbd) { 148*18c2aff7Sartem scmd.uscsi_cdb[1] = 0x8; /* no block descriptors */ 149*18c2aff7Sartem } 150*18c2aff7Sartem scmd.uscsi_cdb[2] = pc; 151*18c2aff7Sartem scmd.uscsi_cdb[7] = (page_len >> 8) & 0xff; 152*18c2aff7Sartem scmd.uscsi_cdb[8] = page_len & 0xff; 153*18c2aff7Sartem 154*18c2aff7Sartem return (uscsi(fd, &scmd) == 0); 155*18c2aff7Sartem } 156*18c2aff7Sartem 157*18c2aff7Sartem /* 158*18c2aff7Sartem * will get the mode page only i.e. will strip off the header. 159*18c2aff7Sartem */ 160*18c2aff7Sartem int 161*18c2aff7Sartem get_mode_page(int fd, int page_no, int pc, int buf_len, uchar_t *buffer, int *plen) 162*18c2aff7Sartem { 163*18c2aff7Sartem int ret; 164*18c2aff7Sartem uchar_t byte2; 165*18c2aff7Sartem uchar_t buf[256]; 166*18c2aff7Sartem uint_t header_len, page_len, copy_cnt; 167*18c2aff7Sartem 168*18c2aff7Sartem byte2 = (uchar_t)(((pc << 6) & 0xC0) | (page_no & 0x3f)); 169*18c2aff7Sartem 170*18c2aff7Sartem /* Ask 254 bytes only to make our IDE driver happy */ 171*18c2aff7Sartem if ((ret = mode_sense(fd, byte2, 1, 254, buf)) == 0) { 172*18c2aff7Sartem return (0); 173*18c2aff7Sartem } 174*18c2aff7Sartem 175*18c2aff7Sartem header_len = 8 + GET16(&buf[6]); 176*18c2aff7Sartem page_len = buf[header_len + 1] + 2; 177*18c2aff7Sartem 178*18c2aff7Sartem copy_cnt = (page_len > buf_len) ? buf_len : page_len; 179*18c2aff7Sartem (void) memcpy(buffer, &buf[header_len], copy_cnt); 180*18c2aff7Sartem 181*18c2aff7Sartem if (plen) { 182*18c2aff7Sartem *plen = page_len; 183*18c2aff7Sartem } 184*18c2aff7Sartem 185*18c2aff7Sartem return (1); 186*18c2aff7Sartem } 187*18c2aff7Sartem 188*18c2aff7Sartem /* Get information about the Logical Unit's capabilities */ 189*18c2aff7Sartem int 190*18c2aff7Sartem get_configuration(int fd, uint16_t feature, int bufsize, uchar_t *buf) 191*18c2aff7Sartem { 192*18c2aff7Sartem struct uscsi_cmd scmd; 193*18c2aff7Sartem char cdb[16]; 194*18c2aff7Sartem 195*18c2aff7Sartem uscsi_cmd_init(&scmd, cdb, sizeof (cdb)); 196*18c2aff7Sartem scmd.uscsi_flags = USCSI_READ|USCSI_SILENT; 197*18c2aff7Sartem scmd.uscsi_timeout = CD_USCSI_TIMEOUT; 198*18c2aff7Sartem scmd.uscsi_cdb[0] = 0x46; /* GET CONFIGURATION */ 199*18c2aff7Sartem scmd.uscsi_cdb[1] = 0x2; /* request type */ 200*18c2aff7Sartem scmd.uscsi_cdb[2] = (feature >> 8) & 0xff; /* starting feature # */ 201*18c2aff7Sartem scmd.uscsi_cdb[3] = feature & 0xff; 202*18c2aff7Sartem scmd.uscsi_cdb[7] = (bufsize >> 8) & 0xff; /* allocation length */ 203*18c2aff7Sartem scmd.uscsi_cdb[8] = bufsize & 0xff; 204*18c2aff7Sartem scmd.uscsi_cdblen = 10; 205*18c2aff7Sartem scmd.uscsi_bufaddr = (char *)buf; 206*18c2aff7Sartem scmd.uscsi_buflen = bufsize; 207*18c2aff7Sartem 208*18c2aff7Sartem return (uscsi(fd, &scmd) == 0); 209*18c2aff7Sartem } 210*18c2aff7Sartem 211*18c2aff7Sartem boolean_t 212*18c2aff7Sartem get_current_profile(int fd, int *profile) 213*18c2aff7Sartem { 214*18c2aff7Sartem size_t i; 215*18c2aff7Sartem uchar_t smallbuf[4]; 216*18c2aff7Sartem size_t buflen; 217*18c2aff7Sartem uchar_t *bufp; 218*18c2aff7Sartem int ret = B_FALSE; 219*18c2aff7Sartem 220*18c2aff7Sartem /* first determine amount of memory needed to hold all profiles */ 221*18c2aff7Sartem if (get_configuration(fd, 0, 4, &smallbuf[0])) { 222*18c2aff7Sartem buflen = GET32(smallbuf) + 4; 223*18c2aff7Sartem bufp = (uchar_t *)malloc(buflen); 224*18c2aff7Sartem 225*18c2aff7Sartem /* now get all profiles */ 226*18c2aff7Sartem if (get_configuration(fd, 0, buflen, bufp)) { 227*18c2aff7Sartem *profile = GET16(&bufp[6]); 228*18c2aff7Sartem ret = B_TRUE; 229*18c2aff7Sartem } 230*18c2aff7Sartem free(bufp); 231*18c2aff7Sartem } 232*18c2aff7Sartem 233*18c2aff7Sartem return (ret); 234*18c2aff7Sartem } 235*18c2aff7Sartem 236*18c2aff7Sartem void 237*18c2aff7Sartem walk_profiles(int fd, int (*f)(void *, int, boolean_t), void *arg) 238*18c2aff7Sartem { 239*18c2aff7Sartem size_t i; 240*18c2aff7Sartem uint16_t profile, current_profile; 241*18c2aff7Sartem uchar_t smallbuf[4]; 242*18c2aff7Sartem size_t buflen; 243*18c2aff7Sartem uchar_t *bufp; 244*18c2aff7Sartem int ret; 245*18c2aff7Sartem 246*18c2aff7Sartem /* first determine amount of memory needed to hold all profiles */ 247*18c2aff7Sartem if (get_configuration(fd, 0, 4, &smallbuf[0])) { 248*18c2aff7Sartem buflen = GET32(smallbuf) + 4; 249*18c2aff7Sartem bufp = (uchar_t *)malloc(buflen); 250*18c2aff7Sartem 251*18c2aff7Sartem /* now get all profiles */ 252*18c2aff7Sartem if (get_configuration(fd, 0, buflen, bufp)) { 253*18c2aff7Sartem current_profile = GET16(&bufp[6]); 254*18c2aff7Sartem for (i = 8 + 4; i < buflen; i += 4) { 255*18c2aff7Sartem profile = GET16(&bufp[i]); 256*18c2aff7Sartem ret = f(arg, profile, (profile == current_profile)); 257*18c2aff7Sartem if (ret == CDUTIL_WALK_STOP) { 258*18c2aff7Sartem break; 259*18c2aff7Sartem } 260*18c2aff7Sartem } 261*18c2aff7Sartem } 262*18c2aff7Sartem 263*18c2aff7Sartem free(bufp); 264*18c2aff7Sartem } 265*18c2aff7Sartem } 266*18c2aff7Sartem 267*18c2aff7Sartem /* retrieve speed list from the Write Speed Performance Descriptor Blocks 268*18c2aff7Sartem */ 269*18c2aff7Sartem void 270*18c2aff7Sartem get_write_speeds(uchar_t *page, int n, intlist_t **speeds, int *n_speeds, intlist_t **speeds_mem) 271*18c2aff7Sartem { 272*18c2aff7Sartem uchar_t *p = page + 2; 273*18c2aff7Sartem int i; 274*18c2aff7Sartem intlist_t **nextp; 275*18c2aff7Sartem intlist_t *current; 276*18c2aff7Sartem boolean_t skip; 277*18c2aff7Sartem 278*18c2aff7Sartem *n_speeds = 0; 279*18c2aff7Sartem *speeds = NULL; 280*18c2aff7Sartem *speeds_mem = (intlist_t *)calloc(n, sizeof (intlist_t)); 281*18c2aff7Sartem if (*speeds_mem == NULL) { 282*18c2aff7Sartem return; 283*18c2aff7Sartem } 284*18c2aff7Sartem 285*18c2aff7Sartem for (i = 0; i < n; i++, p += 4) { 286*18c2aff7Sartem current = &(*speeds_mem)[i]; 287*18c2aff7Sartem current->val = GET16(p); 288*18c2aff7Sartem 289*18c2aff7Sartem /* keep the list sorted */ 290*18c2aff7Sartem skip = B_FALSE; 291*18c2aff7Sartem for (nextp = speeds; *nextp != NULL; nextp = &((*nextp)->next)) { 292*18c2aff7Sartem if (current->val == (*nextp)->val) { 293*18c2aff7Sartem skip = B_TRUE; /* skip duplicates */ 294*18c2aff7Sartem break; 295*18c2aff7Sartem } else if (current->val > (*nextp)->val) { 296*18c2aff7Sartem break; 297*18c2aff7Sartem } 298*18c2aff7Sartem } 299*18c2aff7Sartem if (!skip) { 300*18c2aff7Sartem current->next = *nextp; 301*18c2aff7Sartem *nextp = current; 302*18c2aff7Sartem *n_speeds++; 303*18c2aff7Sartem } 304*18c2aff7Sartem } 305*18c2aff7Sartem } 306*18c2aff7Sartem 307*18c2aff7Sartem void 308*18c2aff7Sartem get_read_write_speeds(int fd, int *read_speed, int *write_speed, 309*18c2aff7Sartem intlist_t **speeds, int *n_speeds, intlist_t **speeds_mem) 310*18c2aff7Sartem { 311*18c2aff7Sartem int page_len; 312*18c2aff7Sartem uchar_t p[254]; 313*18c2aff7Sartem int n; /* number of write speed performance descriptor blocks */ 314*18c2aff7Sartem 315*18c2aff7Sartem *read_speed = *write_speed = 0; 316*18c2aff7Sartem *speeds = *speeds_mem = NULL; 317*18c2aff7Sartem 318*18c2aff7Sartem if (!get_mode_page(fd, 0x2A, 0, sizeof (p), p, &page_len)) { 319*18c2aff7Sartem return; 320*18c2aff7Sartem } 321*18c2aff7Sartem 322*18c2aff7Sartem if (page_len > 8) { 323*18c2aff7Sartem *read_speed = GET16(&p[8]); 324*18c2aff7Sartem } 325*18c2aff7Sartem if (page_len > 18) { 326*18c2aff7Sartem *write_speed = GET16(&p[18]); 327*18c2aff7Sartem } 328*18c2aff7Sartem if (page_len < 28) { 329*18c2aff7Sartem printf("MMC-2\n"); 330*18c2aff7Sartem return; 331*18c2aff7Sartem } else { 332*18c2aff7Sartem printf("MMC-3\n"); 333*18c2aff7Sartem } 334*18c2aff7Sartem 335*18c2aff7Sartem *write_speed = GET16(&p[28]); 336*18c2aff7Sartem 337*18c2aff7Sartem if (page_len < 30) { 338*18c2aff7Sartem return; 339*18c2aff7Sartem } 340*18c2aff7Sartem 341*18c2aff7Sartem /* retrieve speed list */ 342*18c2aff7Sartem n = GET16(&p[30]); 343*18c2aff7Sartem n = min(n, (sizeof (p) - 32) / 4); 344*18c2aff7Sartem 345*18c2aff7Sartem get_write_speeds(&p[32], n, speeds, n_speeds, speeds_mem); 346*18c2aff7Sartem 347*18c2aff7Sartem if (*speeds != NULL) { 348*18c2aff7Sartem *write_speed = max(*write_speed, (*speeds)[0].val); 349*18c2aff7Sartem } 350*18c2aff7Sartem } 351*18c2aff7Sartem 352*18c2aff7Sartem boolean_t 353*18c2aff7Sartem get_disc_info(int fd, disc_info_t *di) 354*18c2aff7Sartem { 355*18c2aff7Sartem struct uscsi_cmd scmd; 356*18c2aff7Sartem char cdb[16]; 357*18c2aff7Sartem uint8_t buf[32]; 358*18c2aff7Sartem int bufsize = sizeof (buf); 359*18c2aff7Sartem 360*18c2aff7Sartem bzero(buf, bufsize); 361*18c2aff7Sartem uscsi_cmd_init(&scmd, cdb, sizeof (cdb)); 362*18c2aff7Sartem scmd.uscsi_flags = USCSI_READ|USCSI_SILENT; 363*18c2aff7Sartem scmd.uscsi_timeout = CD_USCSI_TIMEOUT; 364*18c2aff7Sartem scmd.uscsi_cdb[0] = 0x51; /* READ DISC INFORMATION */ 365*18c2aff7Sartem scmd.uscsi_cdb[7] = (bufsize >> 8) & 0xff; /* allocation length */ 366*18c2aff7Sartem scmd.uscsi_cdb[8] = bufsize & 0xff; 367*18c2aff7Sartem scmd.uscsi_cdblen = 10; 368*18c2aff7Sartem scmd.uscsi_bufaddr = (char *)buf; 369*18c2aff7Sartem scmd.uscsi_buflen = bufsize; 370*18c2aff7Sartem 371*18c2aff7Sartem if ((uscsi(fd, &scmd)) != 0) { 372*18c2aff7Sartem return (B_FALSE); 373*18c2aff7Sartem } 374*18c2aff7Sartem 375*18c2aff7Sartem di->disc_status = buf[2] & 0x03; 376*18c2aff7Sartem di->erasable = buf[2] & 0x10; 377*18c2aff7Sartem if ((buf[21] != 0) && (buf[21] != 0xff)) { 378*18c2aff7Sartem di->capacity = ((buf[21] * 60) + buf[22]) * 75; 379*18c2aff7Sartem } else { 380*18c2aff7Sartem di->capacity = 0; 381*18c2aff7Sartem } 382*18c2aff7Sartem 383*18c2aff7Sartem return (B_TRUE); 384*18c2aff7Sartem } 385*18c2aff7Sartem 386*18c2aff7Sartem /* 387*18c2aff7Sartem * returns current/maximum format capacity in bytes 388*18c2aff7Sartem */ 389*18c2aff7Sartem boolean_t 390*18c2aff7Sartem read_format_capacity(int fd, uint64_t *capacity) 391*18c2aff7Sartem { 392*18c2aff7Sartem struct uscsi_cmd scmd; 393*18c2aff7Sartem char cdb[16]; 394*18c2aff7Sartem uint8_t buf[32]; 395*18c2aff7Sartem int bufsize = sizeof (buf); 396*18c2aff7Sartem uint32_t num_blocks; 397*18c2aff7Sartem uint32_t block_len; 398*18c2aff7Sartem 399*18c2aff7Sartem bzero(buf, bufsize); 400*18c2aff7Sartem uscsi_cmd_init(&scmd, cdb, sizeof (cdb)); 401*18c2aff7Sartem scmd.uscsi_flags = USCSI_READ|USCSI_SILENT; 402*18c2aff7Sartem scmd.uscsi_timeout = CD_USCSI_TIMEOUT; 403*18c2aff7Sartem scmd.uscsi_cdb[0] = 0x23; /* READ FORMAT CAPACITIRES */ 404*18c2aff7Sartem scmd.uscsi_cdb[7] = (bufsize >> 8) & 0xff; /* allocation length */ 405*18c2aff7Sartem scmd.uscsi_cdb[8] = bufsize & 0xff; 406*18c2aff7Sartem scmd.uscsi_cdblen = 12; 407*18c2aff7Sartem scmd.uscsi_bufaddr = (char *)buf; 408*18c2aff7Sartem scmd.uscsi_buflen = bufsize; 409*18c2aff7Sartem 410*18c2aff7Sartem if ((uscsi(fd, &scmd)) != 0) { 411*18c2aff7Sartem return (B_FALSE); 412*18c2aff7Sartem } 413*18c2aff7Sartem 414*18c2aff7Sartem num_blocks = (uint32_t)(buf[4] << 24) + (buf[5] << 16) + (buf[6] << 8) + buf[7]; 415*18c2aff7Sartem block_len = (uint32_t)(buf[9] << 16) + (buf[10] << 8) + buf[11]; 416*18c2aff7Sartem *capacity = (uint64_t)num_blocks * block_len; 417*18c2aff7Sartem 418*18c2aff7Sartem return (B_TRUE); 419*18c2aff7Sartem } 420*18c2aff7Sartem 421*18c2aff7Sartem boolean_t 422*18c2aff7Sartem get_media_info(int fd, struct dk_minfo *minfop) 423*18c2aff7Sartem { 424*18c2aff7Sartem return (ioctl(fd, DKIOCGMEDIAINFO, minfop) != -1); 425*18c2aff7Sartem } 426*18c2aff7Sartem 427*18c2aff7Sartem /* 428*18c2aff7Sartem * given current profile, use the best method for determining 429*18c2aff7Sartem * disc capacity (in bytes) 430*18c2aff7Sartem */ 431*18c2aff7Sartem boolean_t 432*18c2aff7Sartem get_disc_capacity_for_profile(int fd, int profile, uint64_t *capacity) 433*18c2aff7Sartem { 434*18c2aff7Sartem struct dk_minfo mi; 435*18c2aff7Sartem disc_info_t di; 436*18c2aff7Sartem boolean_t ret = B_FALSE; 437*18c2aff7Sartem 438*18c2aff7Sartem switch (profile) { 439*18c2aff7Sartem case 0x08: /* CD-ROM */ 440*18c2aff7Sartem case 0x10: /* DVD-ROM */ 441*18c2aff7Sartem if (get_media_info(fd, &mi) && (mi.dki_capacity > 1)) { 442*18c2aff7Sartem *capacity = mi.dki_capacity * mi.dki_lbsize; 443*18c2aff7Sartem ret = B_TRUE; 444*18c2aff7Sartem } 445*18c2aff7Sartem break; 446*18c2aff7Sartem default: 447*18c2aff7Sartem if (read_format_capacity(fd, capacity) && (*capacity > 0)) { 448*18c2aff7Sartem ret = B_TRUE; 449*18c2aff7Sartem } else if (get_disc_info(fd, &di) && (di.capacity > 0)) { 450*18c2aff7Sartem if (get_media_info(fd, &mi)) { 451*18c2aff7Sartem *capacity = di.capacity * mi.dki_lbsize; 452*18c2aff7Sartem ret = B_TRUE; 453*18c2aff7Sartem } 454*18c2aff7Sartem } 455*18c2aff7Sartem } 456*18c2aff7Sartem 457*18c2aff7Sartem return (ret); 458*18c2aff7Sartem } 459*18c2aff7Sartem 460*18c2aff7Sartem boolean_t 461*18c2aff7Sartem read_toc(int fd, int format, int trackno, int buflen, uchar_t *buf) 462*18c2aff7Sartem { 463*18c2aff7Sartem struct uscsi_cmd scmd; 464*18c2aff7Sartem char cdb[16]; 465*18c2aff7Sartem 466*18c2aff7Sartem bzero(buf, buflen); 467*18c2aff7Sartem uscsi_cmd_init(&scmd, cdb, sizeof (cdb)); 468*18c2aff7Sartem scmd.uscsi_flags = USCSI_READ|USCSI_SILENT; 469*18c2aff7Sartem scmd.uscsi_timeout = CD_USCSI_TIMEOUT; 470*18c2aff7Sartem scmd.uscsi_cdb[0] = 0x43 /* READ_TOC_CMD */; 471*18c2aff7Sartem scmd.uscsi_cdb[2] = format & 0xf; 472*18c2aff7Sartem scmd.uscsi_cdb[6] = trackno; 473*18c2aff7Sartem scmd.uscsi_cdb[8] = buflen & 0xff; 474*18c2aff7Sartem scmd.uscsi_cdb[7] = (buflen >> 8) & 0xff; 475*18c2aff7Sartem scmd.uscsi_cdblen = 10; 476*18c2aff7Sartem scmd.uscsi_bufaddr = (char *)buf; 477*18c2aff7Sartem scmd.uscsi_buflen = buflen; 478*18c2aff7Sartem 479*18c2aff7Sartem if ((uscsi(fd, &scmd)) != 0) { 480*18c2aff7Sartem return (B_FALSE); 481*18c2aff7Sartem } 482*18c2aff7Sartem 483*18c2aff7Sartem return (B_TRUE); 484*18c2aff7Sartem } 485