/* * will get the mode page only i.e. will strip off the header. */ int get_mode_page(int fd, int page_no, int pc, int buf_len, uchar_t *buffer) { int ret; uchar_t byte2, *buf; uint_t header_len, page_len, copy_cnt; byte2 = (uchar_t)(((pc << 6) & 0xC0) | (page_no & 0x3f)); buf = (uchar_t *)my_zalloc(256); /* Ask 254 bytes only to make our IDE driver happy */ ret = mode_sense(fd, byte2, 1, 254, buf); if (ret == 0) { free(buf); return (0); } header_len = 8 + read_scsi16(&buf[6]); page_len = buf[header_len + 1] + 2; copy_cnt = (page_len > buf_len) ? buf_len : page_len; (void) memcpy(buffer, &buf[header_len], copy_cnt); free(buf); return (1); }
void info(void) { uchar_t *toc, *p, *conf; int ret, toc_size; uint_t bsize; size_t cap = 0; char *msg; struct track_info *ti; msg = gettext("Cannot read Table of contents\n"); get_media_type(target->d_fd); (void) printf(gettext("\nDevice : %.8s %.16s\n"), &target->d_inq[8], &target->d_inq[16]); (void) printf(gettext("Firmware : Rev. %.4s (%.12s)\n"), &target->d_inq[32], &target->d_inq[36]); if (check_device(target, CHECK_DEVICE_NOT_READY)) { (void) check_device(target, CHECK_NO_MEDIA | EXIT_IF_CHECK_FAILED); (void) check_device(target, CHECK_DEVICE_NOT_READY | EXIT_IF_CHECK_FAILED); } if (verbose != 0) { /* * Determine the media type by reading the active profile * from the profile list. */ (void) printf(gettext("Media Type : ")); conf = (uchar_t *)my_zalloc(MMC_FTR_HDR_LEN); if (get_configuration(target->d_fd, MMC_FTR_PRFL_LIST, MMC_FTR_HDR_LEN, conf)) print_profile_name(read_scsi16(&conf[6]), 0, 1); else (void) printf(gettext("UNKNOWN\n")); free(conf); /* * Get the start address of the last possible lead out. */ cap = get_last_possible_lba(target); /* * The start address of the last possible leadout will only * be zero if the disc is full or this drive does not support * this method of determining capacity. */ if (cap == 0) cap = read_format_capacity(target->d_fd, &bsize); /* * Since both methods of determining the capacity of the * media count the correct number of blocks, just multiply * the capacity by the block size. */ cap *= target->d_blksize; if (device_type == CD_RW) { (void) printf(gettext("Media Capacity : %.2f MB "), ((double)cap/ONE_MB_BASE2)); } else { /* * For DVD's make sure we print out "Formatted Media * Capacity". Don't do this for CD-RWs as only * DVDs are formatted. */ (void) printf(gettext("Formatted Media Capacity : " "%.2f GB "), ((double)cap/ONE_GB_BASE10)); } cap /= target->d_blksize; (void) printf(gettext("(%u blocks)\n"), (uint_t)cap); } if (!check_device(target, CHECK_MEDIA_IS_NOT_BLANK)) { (void) printf(gettext("Media is blank\n")); exit(0); } /* Find out the number of entries in the toc */ toc = (uchar_t *)my_zalloc(12); if (!read_toc(target->d_fd, 0, 1, 4, toc)) { err_msg(msg); } else { toc_size = 256*toc[0] + toc[1] + 2; free(toc); /* allocate enough space for each track entry */ toc = (uchar_t *)my_zalloc(toc_size); if (!read_toc(target->d_fd, 0, 1, toc_size, toc)) { err_msg(msg); exit(1); } (void) printf("\n"); /* l10n_NOTE : Preserve column numbers of '|' character */ (void) printf(gettext("Track No. |Type |Start address\n")); (void) printf("----------+--------+-------------\n"); /* look at each track and display it's type. */ for (p = &toc[4]; p < (toc + toc_size); p += 8) { if (p[2] != 0xAA) (void) printf(" %-3d |", p[2]); else (void) printf("Leadout |"); (void) printf("%s |", (p[1] & 4) ? gettext("Data ") : gettext("Audio")); (void) printf("%u\n", read_scsi32(&p[4])); } } (void) printf("\n"); ret = read_toc(target->d_fd, 1, 0, 12, toc); if ((ret == 0) || (toc[1] != 0x0a)) /* For ATAPI drives or old Toshiba drives */ ret = read_toc_as_per_8020(target->d_fd, 1, 0, 12, toc); if (ret && (toc[1] == 0x0a)) { (void) printf(gettext("Last session start address: %u\n"), read_scsi32(&toc[8])); } free(toc); ti = (struct track_info *)my_zalloc(sizeof (struct track_info)); if (build_track_info(target, -1, ti) && (ti->ti_flags & TI_NWA_VALID)) { (void) printf(gettext("Next writable address: %u\n"), ti->ti_nwa); } free(ti); exit(0); }
/* * Get current Read or Write Speed from Mode Page 0x2a. * * Use the size of the Page to determine which Multimedia Command * set (MMC) is present. Based on the MMC version, get the * specified Read/Write Speed. * * Note that some MMC versions do not necessarily support a * (current) Read or Write Speed. As a result, this function * _can_ return a value of zero. * * The newer standards (reserve and) mark the field(s) as Obsolete, * yet many vendors populate the Obsolete fields with valid values * (assumedly for backward compatibility). This is important, as * a command like GET PERFORMANCE cannot return _the_ speed; it can * only return a Logical-Block-Address-dependent (LBA) speed. Such * values can vary widely between the innermost and outermost Track. * Mode Page 0x2a is the best solution identifying "the current * (nominal) speed". */ static uint16_t cd_speed_get(cd_device *dev, int cmd) { uchar_t *mp2a; uint16_t rate = 0; int offset; uint_t buflen = 254; /* * Allocate a buffer acceptably larger than any nominal * Page for Page Code 0x2A. */ mp2a = (uchar_t *)my_zalloc(buflen); if (get_mode_page(dev->d_fd, 0x2A, 0, buflen, mp2a) == 0) goto end; /* Determine MMC version based on 'Page Length' field */ switch (mp2a[1]) { case 0x14: /* MMC-1 */ if (debug) (void) printf("Mode Page 2A: MMC-1\n"); offset = (cmd == GET_READ_SPEED) ? 14 : 20; rate = read_scsi16(&mp2a[offset]); break; case 0x18: /* MMC-2 */ if (debug) (void) printf("Mode Page 2A: MMC-2;" " Read and Write Speeds are " "obsolete\n"); /* see if "Obsolete" values are valid: */ offset = (cmd == GET_READ_SPEED) ? 14 : 20; rate = read_scsi16(&mp2a[offset]); break; default: /* MMC-3 or newer */ if (debug) (void) printf("Mode Page 2A: MMC-3 or" " newer; Read Speed is obsolete.\n"); if (cmd == GET_READ_SPEED) { /* this is Obsolete, but try it */ offset = 14; rate = read_scsi16(&mp2a[offset]); } else { /* Write Speed is not obsolete */ offset = 28; rate = read_scsi16(&mp2a[offset]); if (rate == 0) { /* * then try an Obsolete field * (but this shouldn't happen!) */ offset = 20; rate = read_scsi16(&mp2a[offset]); } } break; } end: free(mp2a); if (debug) (void) printf("cd_speed_get: %s Speed is " "%uX\n", (cmd == GET_READ_SPEED) ? "Read" : "Write", cdrw_bandwidth_to_x(rate)); return (rate); }
/* * The size of the last track in one of the first N - 1 sessions of an * N-session (N > 1) disc is reported incorrectly by some drives and calculated * incorrectly for others, because a pre-gap/lead-out/lead-in section that ends * a session is erroneously considered part of that track. This function checks * for this corner case, and adjusts the track size if necessary. */ static int check_track_size(cd_device *dev, int trk_num, struct track_info *tip) { size_t raw_toc_len; uchar_t *raw_toc; rtoc_hdr_t hdr; uint32_t sess_leadout_lba; int sess_last_trk_num; int trk_sess_num; uint32_t trk_size; /* Request Raw TOC Header for session count. */ if (read_toc(dev->d_fd, FORMAT_RAW_TOC, 1, sizeof (rtoc_hdr_t), (uchar_t *)&hdr) != 1) return (0); /* Is this a multi-session medium? */ if (hdr.rh_last_sess_num > hdr.rh_first_sess_num) { /* Yes; request entire Raw TOC. */ raw_toc_len = read_scsi16(&hdr.rh_data_len1) + RTOC_DATA_LEN_SZ; raw_toc = (uchar_t *)my_zalloc(raw_toc_len); if (read_toc(dev->d_fd, FORMAT_RAW_TOC, 1, raw_toc_len, raw_toc) != 1) goto fail; if (rtoc_get_trk_sess_num(raw_toc, raw_toc_len, trk_num, &trk_sess_num) != 1) goto fail; tip->ti_session_no = trk_sess_num; tip->ti_flags |= TI_SESSION_NO_VALID; /* Is the track in one of the first N - 1 sessions? */ if (trk_sess_num < hdr.rh_last_sess_num) { if (rtoc_get_sess_last_trk_num(raw_toc, raw_toc_len, trk_sess_num, &sess_last_trk_num) != 1) goto fail; /* Is the track the last track in the session? */ if (trk_num == sess_last_trk_num) { if (rtoc_get_sess_leadout_lba(raw_toc, raw_toc_len, trk_sess_num, &sess_leadout_lba) != 1) goto fail; trk_size = sess_leadout_lba - tip->ti_start_address; /* Fix track size if it was too big. */ if (tip->ti_track_size > trk_size) tip->ti_track_size = trk_size; } } free(raw_toc); } return (1); fail: free(raw_toc); return (0); }