/* * Find out media capacity. */ uint32_t get_last_possible_lba(cd_device *dev) { uchar_t *di; uint32_t cap; di = (uchar_t *)my_zalloc(DISC_INFO_BLOCK_SIZE); if (!read_disc_info(dev->d_fd, di)) { free(di); return (0); } /* * If we have a DVD+R this field is an LBA. If the media is * a CD-R/W the field is MSF formatted. Otherwise this field * is not valid and will be zero. */ if (device_type == DVD_PLUS) { if (read_scsi32(&di[20]) != 0xffffffff) { cap = read_scsi32(&di[20]); } else { cap = 0; } } else { if ((di[21] != 0) && (di[21] != 0xff)) { cap = MSF2LBA(di[21], di[22], di[23]); } else { cap = 0; } } free(di); return (cap); }
/* * Find out media capacity. */ int get_last_possible_lba(cd_device *dev) { uchar_t *di; int cap; di = (uchar_t *)my_zalloc(DISC_INFO_BLOCK_SIZE); if (!read_disc_info(dev->d_fd, di)) { free(di); return (0); } if ((di[21] != 0) && (di[21] != 0xff)) { cap = ((di[21] * 60) + di[22]) * 75; } else { cap = 0; } free(di); return (cap); }
/* * Close session. This will write TOC. */ int finalize(cd_device *dev) { uchar_t *di; int count, ret, err; int immediate; int finalize_max; /* * For ATAPI devices we will use the immediate mode and will * poll the command for completion so that this command may * not hog the channel. But for SCSI, we will use the treditional * way of issuing the command with a large enough timeout. This * is done because immediate mode was designed for ATAPI and some * SCSI RW drives might not be even tested with it. */ if ((dev->d_inq[2] & 7) != 0) { /* SCSI device */ immediate = 0; } else { /* non-SCSI (e.g ATAPI) device */ immediate = 1; } /* We need to close track before close session */ if (device_type == DVD_PLUS) { if (!close_track(dev->d_fd, 0, 0, immediate)) return (0); } if (!close_track(dev->d_fd, 0, 1, immediate)) { /* * For DAO mode which we use for DVD-RW, the latest MMC * specification does not mention close_track. Some * newer drives will return an ILLEGAL INSTRUCTION * which we will ignore. We have also found a Panasonic * drive which will return a MEDIA ERROR. It is safe * to ignore both errors as this is not needed for * these drives. * This is kept for older drives which had needed * us to issue close_track to flush the cache fully. * once we are certain these drives have cleared the * market, this can be removed. */ if (device_type == DVD_MINUS) { return (0); } } else { if (!immediate) return (1); } if (immediate) { (void) sleep(10); di = (uchar_t *)my_zalloc(DISC_INFO_BLOCK_SIZE); err = 0; if (device_type == CD_RW) { /* Finalization should not take more than 6 minutes */ finalize_max = FINALIZE_TIMEOUT; } else { /* some DVD-RW drives take longer than 6 minutes */ finalize_max = FINALIZE_TIMEOUT*2; } for (count = 0; count < finalize_max; count++) { ret = read_disc_info(dev->d_fd, di); if (ret != 0) break; if (uscsi_status != 2) err = 1; if (SENSE_KEY(rqbuf) == 2) { /* not ready but not becoming ready */ if (ASC(rqbuf) != 4) err = 1; } else if (SENSE_KEY(rqbuf) == 5) { /* illegal mode for this track */ if (ASC(rqbuf) != 0x64) err = 1; } else { err = 1; } if (err == 1) { if (debug) { (void) printf("Finalization failed\n"); (void) printf("%x %x %x %x\n", uscsi_status, SENSE_KEY(rqbuf), ASC(rqbuf), ASCQ(rqbuf)); } free(di); return (0); } if (uscsi_status == 2) { int i; /* illegal field in command packet */ if (ASC(rqbuf) == 0x24) { /* print it out! */ (void) printf("\n"); for (i = 0; i < 18; i++) (void) printf("%x ", (unsigned)(rqbuf[i])); (void) printf("\n"); } } (void) sleep(5); } free(di); } return (ret); }