1 #ifndef _LARGEFILE_SOURCE
2 #define _LARGEFILE_SOURCE
3 #endif
4 #ifndef _LARGEFILE64_SOURCE
5 #define _LARGEFILE64_SOURCE
6 #endif
7 #ifndef _FILE_OFFSET_BITS
8 #define _FILE_OFFSET_BITS 64
9 #endif
10 #if defined(__linux)
11 /* ... and "engage" glibc large file support */
12 #ifndef _GNU_SOURCE
13 #define _GNU_SOURCE
14 #endif
15 #endif
16
17 #include "transport.hxx"
18
19 #include <time.h>
20 #include <sys/types.h>
21
22 #define SIGS_BLOCK 1
23 #define SIGS_UNBLOCK 0
24 extern "C" void sigs_mask (int);
25 extern "C" void atsignals (void (*)(void));
26
27 #define DVD_1X 1352 // 1385 * 1000 / 1024
28 #define BD_1X 4390 // 4495.5 * 1000 / 1024
29
30 static int media_written=0,next_track=1,
31 is_dao=0,quickgrown=0,do_reload=1,
32 _1x=DVD_1X,_64k=0,bdr_plus_pow=0;
33 static unsigned int stdnap=(256*1000)/DVD_1X,// measured in milliseconds
34 buf_size=512; // measured in KBs
35 static class __velocity__ {
36 private:
37 int value;
38 public:
operator =(int v)39 int operator=(int v) { if (v>=_1x) stdnap=(buf_size*500)/v;
40 else stdnap=(buf_size*500)/_1x;
41 return value = v;
42 }
operator int()43 operator int() { return value; }
44 } velocity;
45
46 static void *ioctl_handle=(void *)-1;
47 #ifndef ioctl_fd
48 #define ioctl_fd ((long)ioctl_handle)
49 #endif
50
51 static unsigned int next_wr_addr=1; // it starts as boolean
52 static unsigned int dao_blocks=0;
53 static unsigned int cap2kstart=0;
54 static unsigned char formats[260],disc_info[32];
55
56 extern "C" {
57 extern int dvd_compat,test_write,no_reload,mmc_profile,_argc,
58 wrvfy,no_opc,spare;
59 extern double speed_factor;
60 extern char *ioctl_device,**_argv;
61 }
62
63 extern "C"
__1x(void)64 int __1x (void) { return _1x; }
65
66 extern "C"
fumount(int fd)67 int fumount (int fd)
68 { Scsi_Command cmd;
69 return cmd.umount(fd);
70 }
71
72 extern "C"
media_reload(char * name=NULL,struct stat * sb=NULL,unsigned int cap2k=0)73 int media_reload (char *name=NULL,struct stat *sb=NULL,unsigned int cap2k=0)
74 { if (name==NULL)
75 { Scsi_Command cmd(ioctl_handle);
76
77 pioneer_stop (cmd);
78
79 #if defined(RELOAD_NEVER_NEEDED)
80 #undef RELOAD_NEVER_NEEDED
81 #define RELOAD_NEVER_NEEDED 1
82 #else
83 #define RELOAD_NEVER_NEEDED 0
84 #endif
85 if (RELOAD_NEVER_NEEDED || no_reload>0)
86 { cmd[0] = 0x1E; // ALLOW MEDIA REMOVAL
87 cmd[5] = 0;
88 cmd.transport ();
89
90 return (errno=0);
91 }
92 #if !RELOAD_NEVER_NEEDED
93
94 char fdstr[12],cap2kstr[12];
95 int n;
96
97 if ((n=fcntl (ioctl_fd,F_GETFD))<0) n=0;
98 fcntl (ioctl_fd,F_SETFD,n&~FD_CLOEXEC);
99
100 sprintf (fdstr,"%ld",ioctl_fd);
101 sprintf (cap2kstr,"%u",cap2kstart);
102 execlp(_argv[0],no_reload<0?"-eject":"-reload",
103 fdstr,ioctl_device,cap2kstr,(void *)NULL);
104 }
105 else
106 {
107 { Scsi_Command cmd;
108 unsigned char c[8];
109 unsigned int cap2kend;
110
111 if (!cmd.associate (name,sb)) return 1;
112
113 cmd[0] = 0x25; // READ CAPACITY
114 cmd[9] = 0;
115 if (!cmd.transport (READ,c,sizeof(c)))
116 cap2kend = c[0]<<24|c[1]<<16|c[2]<<8|c[3];
117 else
118 cap2kend = (unsigned int)-1;
119
120 if (cmd.is_reload_needed(cap2k==cap2kend))
121 { fprintf (stderr,"%s: reloading tray\n",name);
122 cmd[0] = 0x1E; // ALLOW MEDIA REMOVAL
123 cmd[5] = 0;
124 if (cmd.transport ()) return 1;
125
126 while (1) // Pioneer DVR-x05 needs this...
127 { cmd[0] = 0x1B; // START/STOP UNIT
128 cmd[1] = 0x1; // "IMMED"
129 cmd[4] = 0x2; // "Eject"
130 cmd[5] = 0;
131 if (cmd.transport() == 0x20407) // "OP IN PROGRESS"
132 { poll (NULL,0,333);
133 continue;
134 }
135 break;
136 }
137 // yes, once again, non-"IMMED"...
138 cmd[0] = 0x1B; // START/STOP UNIT
139 cmd[4] = 0x2; // "Eject"
140 cmd[5] = 0;
141 if (cmd.transport()) return 1;
142 }
143 #if defined(__sun) || defined(sun)
144 else if (volmgt_running())
145 { setuid(getuid());
146 execl("/usr/bin/volrmmount","volrmmount","-i",name,(void*)NULL);
147 return 0; // not normally reached
148 }
149 else if (1)
150 { char srlink[256],*dsk;
151 static char dev[]="/dev/dsk/";
152 int len;
153
154 /* this basically handles /dev/rsrN link */
155 if ((len=readlink(name,srlink,sizeof(srlink)-1))>0 &&
156 (srlink[len]='\0',(dsk=strstr(srlink,"dsk/"))!=NULL))
157 { name=(char *)alloca(sizeof(dev)+strlen(dsk+4)+1);
158 strcpy(name,dev), strcat(name,dsk+4);
159 }
160 setuid(getuid());
161 execl("/usr/bin/rmmount","rmmount",name,(void*)NULL);
162 return 0; // not reached on SunOS 5.11
163 }
164 #endif
165 else return 0; // m-m-m-m! patched kernel:-)
166 }
167 if (no_reload>=0)
168 { Scsi_Command cmd;
169 if (cmd.associate (name,sb))
170 { cmd[0] = 0x1B; // START/STOP UNIT
171 cmd[1] = 0x1; // "IMMED"
172 cmd[4] = 0x3; // "Load"
173 cmd[5] = 0;
174 cmd.transport ();
175 }
176 errno=0; // ignore all errors on load
177 }
178 return 0;
179 #endif
180 }
181
182 return 1;
183 }
184
185 extern "C"
get_mmc_profile(void * fd)186 int get_mmc_profile (void *fd)
187 { Scsi_Command cmd(fd);
188 unsigned char buf[8],inq[128];
189 int profile=0,once=1,blank=0,err;
190 unsigned int len;
191
192 #if defined(__APPLE__) && defined(__MACH__)
193 // The reason for Mac OS X specific MMCIO appearing here and there
194 // is that raw SCSI requires exclusive access, while I'm not ready
195 // to give it up yet...
196
197 // I don't call INQUIRY, because kernel ensures that
198 // MMCDeviceInterface is attached to an MMC device...
199 if ((err=MMCIO(fd,GetConfiguration,0,0,buf,sizeof(buf))))
200 sperror ("GET CONFIGURATION",err),
201 exit (FATAL_START(errno));
202
203 profile = buf[6]<<8|buf[7];
204 #else
205 // INQUIRY is considered to be "non-intrusive" in a sense that
206 // it won't interfere with any other operation nor clear sense
207 // data, which might be important to retain for security reasons.
208
209 cmd[0] = 0x12; // INQUIRY
210 cmd[4] = 36;
211 cmd[5] = 0;
212 if ((err=cmd.transport(READ,inq,36)))
213 sperror ("INQUIRY",err),
214 exit (FATAL_START(errno));
215
216 // make sure we're talking to MMC unit, for security reasons...
217 if ((inq[0]&0x1F) != 5)
218 fprintf (stderr,":-( not an MMC unit!\n"),
219 exit (FATAL_START(EINVAL));
220
221 do {
222 cmd[0] = 0x46;
223 cmd[8] = sizeof(buf);
224 cmd[9] = 0;
225 if ((err=cmd.transport(READ,buf,sizeof(buf))))
226 sperror ("GET CONFIGURATION",err),
227 fprintf (stderr,":-( non-MMC unit?\n"),
228 exit (FATAL_START(errno));
229
230 if ((profile = buf[6]<<8|buf[7]) || !once) break;
231
232 // no media?
233 cmd[0] = 0; // TEST UNIT READY
234 cmd[5] = 0;
235 if ((cmd.transport()&0xFFF00) != 0x23A00) break;
236
237 // try to load tray...
238 cmd[0] = 0x1B; // START/STOP UNIT
239 cmd[4] = 0x3; // "Load"
240 cmd[5] = 0;
241 if ((err=cmd.transport ()))
242 sperror ("LOAD TRAY",err),
243 exit (FATAL_START(errno));
244
245 #if 1
246 wait_for_unit (cmd);
247 #else
248 // consume sense data, most likely "MEDIA MAY HAVE CHANGED"
249 cmd[0] = 0; // TEST UNIT READY
250 cmd[5] = 0;
251 if ((err=cmd.transport ()) == -1)
252 sperror ("TEST UNIT READY",err),
253 exit (FATAL_START(errno));
254 #endif
255 } while (once--);
256 #endif // !Mac OS X
257
258 if (profile==0 || (profile&0x70)==0) // no or non-DVD/BD media...
259 return profile;
260
261 if ((profile&0xF0) == 0x40)
262 { unsigned char header[16];
263
264 _1x = BD_1X;
265 _64k = 1;
266
267 if (profile==0x41) // BD-R SRM
268 { // Check for POW feature...
269 #if defined(__APPLE__) && defined(__MACH__)
270 err = MMCIO(fd,GetConfiguration,2,0x38,header,16);
271 #else
272 cmd[0] = 0x46; // GET CONFIGURATION
273 cmd[1] = 2; // ask for the only feature...
274 cmd[3] = 0x38; // the "BD-R Pseudo-Overwrite" one
275 cmd[8] = 16; // The feature should be there, right?
276 cmd[9] = 0;
277 err = cmd.transport (READ,header,16);
278 #endif
279 if (err==0 &&
280 (header[0]<<24|header[1]<<16|header[2]<<8|header[3])>=12 &&
281 (header[8+2]&1)==1)
282 bdr_plus_pow=1;
283 }
284
285 }
286
287 #if defined(__APPLE__) && defined(__MACH__)
288 err = MMCIO(fd,ReadDiscInformation,disc_info,sizeof(disc_info));
289 #else
290 cmd[0] = 0x51; // READ DISC INFORMATION
291 cmd[8] = sizeof(disc_info);
292 cmd[9] = 0;
293 err = cmd.transport (READ,disc_info,sizeof(disc_info));
294 #endif
295 if (err)
296 sperror ("READ DISC INFORMATION",err),
297 exit (FATAL_START(errno));
298
299 // see if it's blank media
300 if ((disc_info[2]&3) == 0) blank=0x10000;
301
302 if (profile != 0x1A && profile != 0x2A && // DVD+RW
303 profile != 0x13 && profile != 0x12 && // DVD-R[AM]
304 profile != 0x43 && !(profile == 0x41 && blank)) // BD-R[E]
305 return blank|profile;
306
307 #if defined(__APPLE__) && defined(__MACH__)
308 err = MMCIO(fd,ReadFormatCapacities,formats,12);
309 #else
310 cmd[0] = 0x23; // READ FORMAT CAPACITIES
311 cmd[8] = 12;
312 cmd[9] = 0;
313 err = cmd.transport (READ,formats,12);
314 #endif
315 if (err)
316 sperror ("READ FORMAT CAPACITIES",err),
317 exit (FATAL_START(errno));
318
319 len = formats[3];
320 if (len&7 || len<16)
321 fprintf (stderr,":-( FORMAT allocaion length isn't sane"),
322 exit (FATAL_START(EINVAL));
323
324 #if defined(__APPLE__) && defined(__MACH__)
325 err = MMCIO(fd,ReadFormatCapacities,formats,4+len);
326 #else
327 cmd[0] = 0x23; // READ FORMAT CAPACITIES
328 cmd[7] = (4+len)>>8;
329 cmd[8] = (4+len)&0xFF;
330 cmd[9] = 0;
331 err = cmd.transport (READ,formats,4+len);
332 #endif
333 if (err)
334 sperror ("READ FORMAT CAPACITIES",err),
335 exit (FATAL_START(errno));
336
337 if (len != formats[3])
338 fprintf (stderr,":-( parameter length inconsistency\n"),
339 exit(FATAL_START(EINVAL));
340
341 // see if it's not formatted
342 if ((formats[8]&3) != 2) blank = 0x10000;
343
344 return blank|profile;
345 }
346
get_2k_capacity(Scsi_Command & cmd,void * fd=NULL)347 static unsigned int get_2k_capacity (Scsi_Command &cmd,void *fd=NULL)
348 { unsigned char buf[32];
349 unsigned int ret=0;
350 unsigned int nwa,free_blocks;
351 int i,obligatory,len,err;
352
353 obligatory=0x00;
354 switch (mmc_profile&0xFFFF)
355 { case 0x1A: // DVD+RW
356 obligatory=0x26;
357 case 0x13: // DVD-RW Restricted Overwrite
358 for (i=8,len=formats[3];i<len;i+=8)
359 if ((formats [4+i+4]>>2) == obligatory) break;
360
361 if (i==len)
362 { fprintf (stderr,":-( can't locate obligatory format descriptor\n");
363 return 0;
364 }
365
366 ret = formats[4+i+0]<<24;
367 ret |= formats[4+i+1]<<16;
368 ret |= formats[4+i+2]<<8;
369 ret |= formats[4+i+3];
370 nwa = formats[4+5]<<16|formats[4+6]<<8|formats[4+7];
371 if (nwa>2048) ret *= nwa/2048;
372 else if (nwa<2048) ret /= 2048/nwa;
373 break;
374
375 case 0x12: // DVD-RAM
376 // As for the moment of this writing I don't format DVD-RAM.
377 // Therefore I just pull formatted capacity for now...
378 ret = formats[4+0]<<24;
379 ret |= formats[4+1]<<16;
380 ret |= formats[4+2]<<8;
381 ret |= formats[4+3];
382 nwa = formats[4+5]<<16|formats[4+6]<<8|formats[4+7];
383 if (nwa>2048) ret *= nwa/2048;
384 else if (nwa<2048) ret /= 2048/nwa;
385 break;
386
387 case 0x11: // DVD-R
388 case 0x14: // DVD-RW Sequential
389 case 0x15: // DVD-R Dual Layer Sequential
390 case 0x16: // DVD-R Dual Layer Jump
391 case 0x1B: // DVD+R
392 case 0x2B: // DVD+R Double Layer
393 case 0x41: // BD-R SRM
394 #if defined(__APPLE__) && defined(__MACH__)
395 if (fd)
396 err = MMCIO(fd,ReadTrackInformation,1,next_track,buf,sizeof(buf));
397 else
398 #endif
399 { cmd[0] = 0x52; // READ TRACK INFORMATION
400 cmd[1] = 1;
401 cmd[4] = next_track>>8;
402 cmd[5] = next_track&0xFF; // last track, set up earlier
403 cmd[8] = sizeof(buf);
404 cmd[9] = 0;
405 err = cmd.transport (READ,buf,sizeof(buf));
406 }
407 if (err)
408 { sperror ("READ TRACK INFORMATION",err);
409 return 0;
410 }
411
412 nwa = 0;
413 if (buf[7]&1) // NWA_V
414 { nwa = buf[12]<<24;
415 nwa |= buf[13]<<16;
416 nwa |= buf[14]<<8;
417 nwa |= buf[15];
418 }
419 free_blocks = buf[16]<<24;
420 free_blocks |= buf[17]<<16;
421 free_blocks |= buf[18]<<8;
422 free_blocks |= buf[19];
423 ret = nwa + free_blocks;
424 break;
425
426 case 0x43: // BD-RE
427 // just pull formatted capacity for now...
428 ret = formats[4+0]<<24;
429 ret |= formats[4+1]<<16;
430 ret |= formats[4+2]<<8;
431 ret |= formats[4+3];
432 break;
433
434 default:
435 break;
436 }
437
438 return ret;
439 }
440
441 extern "C"
get_capacity(void * fd)442 off64_t get_capacity (void *fd)
443 { Scsi_Command cmd(fd);
444 return (off64_t)get_2k_capacity(cmd,fd)*2048;
445 }
446
447 extern "C"
get_buffer_stats(void * fd)448 float get_buffer_stats (void *fd)
449 { Scsi_Command cmd(fd);
450 unsigned char bcap[12];
451 unsigned int bsize,bfree;
452 int err;
453
454 cmd[0] = 0x5C; // READ BUFFER CAPACITY
455 cmd[8] = sizeof(bcap);
456 cmd[9] = 0;
457 if ((err=cmd.transport (READ,bcap,sizeof(bcap))))
458 return -1.0f;
459
460 bsize = bcap[4]<<24|bcap[5]<<16|bcap[6]<<8|bcap[7];
461 bfree = bcap[8]<<24|bcap[9]<<16|bcap[10]<<8|bcap[11];
462
463 return bsize ? (1.0f - (float)bfree/(float)bsize) : 0.0f;
464 }
465
poor_mans_pwrite64(int fd,const void * _buff,size_t size,off64_t foff)466 ssize_t poor_mans_pwrite64 (int fd,const void *_buff,size_t size,off64_t foff)
467 { Scsi_Command cmd(ioctl_handle); /* screw first argument */
468 unsigned char bcap[12];
469 const unsigned char *buff=(const unsigned char *)_buff;
470 unsigned int lba,nbl,bsize,bfree;
471 int retries=0,errcode;
472 static int dao_toggle=-1;
473
474 if (foff&0x7FFF || size&0x7FFF) // 32K block size
475 return (errno=EINVAL,-1);
476
477 lba = (unsigned int)(foff/2048);
478 nbl = (unsigned int)(size/2048);
479
480 if (!media_written && next_wr_addr)
481 { if ((lba+nbl) <= next_wr_addr)
482 return size;
483 else if (next_wr_addr > lba)
484 nbl -= (next_wr_addr-lba),
485 size -= (next_wr_addr-lba)<<11,
486 buff += (next_wr_addr-lba)<<11,
487 lba = next_wr_addr;
488 }
489 #if defined(__sun) || defined(sun)
490 else next_wr_addr = lba;
491 #endif
492
493 if (dao_toggle<0) dao_toggle=is_dao;
494
495 { static unsigned int first_wr_addr=0;
496
497 if (!media_written)
498 { sigs_mask (SIGS_BLOCK); first_wr_addr = lba; }
499 else if (lba >= (first_wr_addr+buf_size/2)) // measured in 2KBs!
500 { sigs_mask (SIGS_UNBLOCK); }
501 }
502
503 if (dao_blocks!=0 && (lba+nbl)>dao_blocks)
504 nbl = dao_blocks-lba;
505
506 while (1)
507 { cmd[0] = wrvfy?0x2E:0x2A; // WRITE [AND VERIFY] (10)
508 cmd[2] = (lba>>24)&0xff; // Logical Block Addrss
509 cmd[3] = (lba>>16)&0xff;
510 cmd[4] = (lba>>8)&0xff;
511 cmd[5] = lba&0xff;
512 cmd[7] = (nbl>>8)&0xff;
513 cmd[8] = nbl&0xff;
514 cmd[9] = 0;
515 #if 0
516 cmd[0] = 0xAA; // WRITE(12)
517 cmd[2] = (lba>>24)&0xff; // Logical Block Addrss
518 cmd[3] = (lba>>16)&0xff;
519 cmd[4] = (lba>>8)&0xff;
520 cmd[5] = lba&0xff;
521 cmd[8] = (nbl>>8)&0xff;
522 cmd[9] = nbl&0xff;
523 cmd[10] = 0x80; // "Streaming"
524 cmd[11] = 0;
525 #endif
526 //
527 // First writes can be long, especially in DAO mode...
528 // I wish I could complement this with "if (lba==0),"
529 // but some units might choose to fill the buffer before
530 // they take the first nap...
531 //
532 cmd.timeout(dao_toggle?180:60);
533 //
534 // It should also be noted that under Linux these values
535 // (if actually respected by kernel!) can turn out bogus.
536 // The problem is that I scale them to milliseconds as
537 // documentation requires/implies, while kernel treats
538 // them as "jiffies." I could/should have used HZ macro
539 // (or sysconf(_SC_CLK_TCK)), but recent kernels maintain
540 // own higher HZ value and disrespects the user-land one.
541 // Sending them down as milliseconds is just safer...
542 //
543 if (!(errcode=cmd.transport (WRITE,(void *)buff,size)))
544 break;
545
546 //--- WRITE failed ---//
547 #if defined(__sun) || defined(sun)
548 //
549 // Solaris can slice USB WRITEs to multiple ones. Here I try
550 // to find out which slice has failed. I expect we get here
551 // only when we re-enter the loop...
552 //
553 if (lba==next_wr_addr &&
554 errcode==0x52102) // "INVALID ADDRESS FOR WRITE"
555 { unsigned char track[32];
556
557 cmd[0] = 0x52; // READ TRACK INFORMATION
558 cmd[1] = 1;
559 cmd[4] = next_track>>8;
560 cmd[5] = next_track&0xFF;
561 cmd[8] = sizeof(track);
562 cmd[9] = 0;
563 if (!cmd.transport (READ,track,sizeof(track)))
564 { if (track[7]&1) // NWA_V
565 { next_wr_addr = track[12]<<24;
566 next_wr_addr |= track[13]<<16;
567 next_wr_addr |= track[14]<<8;
568 next_wr_addr |= track[15];
569 if (lba<next_wr_addr && (lba+nbl)>next_wr_addr)
570 { nbl -= next_wr_addr-lba,
571 size -= (next_wr_addr-lba)<<11,
572 buff += (next_wr_addr-lba)<<11,
573 lba = next_wr_addr;
574 continue;
575 }
576 }
577 }
578 }
579 #endif
580
581 if (errcode==0x20408) // "LONG WRITE IN PROGRESS"
582 { // Apparently only Pioneer units do this...
583 if (velocity == 0)
584 { if (handle_events(cmd) & (1<<6))
585 continue;
586 goto sync_cache;
587 }
588
589 cmd[0] = 0x5C; // READ BUFFER CAPACITY
590 cmd[8] = sizeof(bcap);
591 cmd[9] = 0;
592 if (cmd.transport (READ,bcap,sizeof(bcap)))
593 bfree=0, bsize=buf_size;
594 else
595 { bsize = bcap[4]<<24|bcap[5]<<16|bcap[6]<<8|bcap[7];
596 bfree = bcap[8]<<24|bcap[9]<<16|bcap[10]<<8|bcap[11];
597 bsize /= 1024, bfree /= 1024; // xlate to KB
598 }
599 // check for sanity and drain 1/2 of the buffer
600 if (bsize < buf_size/2) bsize = buf_size/2;
601 else bsize /= 2;
602 if (bfree > bsize) bfree = bsize;
603
604 int msecs=0;
605
606 if ((msecs=(bsize-bfree)*1000) > velocity)
607 { msecs /= velocity;
608 retries++;
609 if (dao_toggle) dao_toggle=-1;
610 }
611 else // lots of free buffer reported?
612 { if (dao_toggle)
613 { dao_toggle=-1;
614 if ((handle_events(cmd) & (1<<6)))
615 continue;
616 msecs = bsize*1000;
617 msecs /= velocity;
618 }
619 else if (!retries++) continue;
620 // Pioneer units seem to return bogus values at high
621 // velocities now and then... I reserve for 4 ECC
622 // blocks, which is ~6 ms at 16x. But note that some
623 // OSes, Linux 2.4 among then, will nap for 10 or 20.
624 msecs = (4*32*1000)/velocity;
625 }
626
627 // Retry values were increased because high-speed units
628 // start recordings at only portion of velocity and it
629 // takes more retries to write lead-in... Another common
630 // reason for stucks are recalibrations at zone edges...
631 if (retries > (dao_toggle?768:192))
632 fprintf (stderr,":-? the LUN appears to be stuck "
633 "writing LBA=%xh, keep retrying in %dms\n",
634 lba,msecs),
635 retries=1;
636
637 if (msecs>=0)
638 { poll (NULL,0,msecs);
639 continue;
640 }
641
642 lba |= 0x80000000; // signal insane bfree...
643 }
644 else if (lba==0 && errcode==0x20401) // "IN PROCESS OF BECOMING READY"
645 { if ((handle_events(cmd) & (1<<6)))
646 continue;
647 if (++retries > 3)
648 { fprintf (stderr,":-! the LUN is still in process of becoming ready, "
649 "retrying in 5 secs...\n"),
650 retries=0;
651 sigs_mask (SIGS_UNBLOCK);
652 poll (NULL,0,5000);
653 }
654 else
655 sigs_mask (SIGS_UNBLOCK),
656 poll (NULL,0,stdnap);
657 continue;
658 }
659 else if (errcode==0x20404 || // "FORMAT IN PROGRESS"
660 errcode==0x20407 || // "OPERATION IN PROGRESS"
661 errcode==0x52C00) // "COMMAND SEQUENCE ERROR"
662 { // Happens under automounter control? In general I recommend
663 // to disable it! This code is a tribute to users who disregard
664 // the instructions...
665 sync_cache:
666 // should I check if lba+nbl is multiple of 64K in BD case?
667 cmd[0] = 0x35; // SYNC CACHE
668 cmd[9] = 0;
669 if (!cmd.transport())
670 { if (++retries > 1)
671 { fprintf (stderr,":-! the LUN appears to be stuck at %xh, "
672 "retrying in 5 secs...\n",lba),
673 retries=0;
674 sigs_mask (SIGS_UNBLOCK);
675 poll (NULL,0,5000);
676 }
677 else if (errcode==0x52C00)
678 fprintf (stderr,":-! \"COMMAND SEQUENCE ERROR\"@LBA=%xh. "
679 "Is media being read?\n",lba);
680 continue;
681 }
682 lba |= 0x40000000; // signal "can't SYNC CACHE"
683 }
684 { char cmdname[64];
685 sprintf (cmdname,"WRITE@LBA=%xh",lba),
686 sperror (cmdname,errcode);
687 }
688 if (lba==0)
689 { if (ASC(errcode)==0x30)
690 fprintf (stderr,":-( media is not formatted or unsupported.\n");
691 else if ((mmc_profile&0xFFFF)==0x14 /*&& ASC(errcode)==0x64*/)
692 fprintf (stderr,":-( attempt to re-run with "
693 "-dvd-compat -dvd-compat to engage DAO or "
694 "apply full blanking procedure\n");
695 }
696 #if 1 // safety net: leave DL sessions open and resumable...
697 if ((mmc_profile&0xFFFF)==0x2B && errcode!=0x52100) media_written=0;
698 #endif
699 return -1;
700 }
701
702 next_wr_addr = lba+nbl;
703 media_written = 1;
704
705 if (dao_toggle<0) dao_toggle=0;
706
707 return size;
708 }
709
710 // spare == -1 "format without spare"
711 // spare == 0 "format with minimal spare"
712 // spare > 0 "format with default descriptor"
bd_r_format(Scsi_Command & cmd)713 static void bd_r_format (Scsi_Command &cmd)
714 { int err,i,len;
715 unsigned char descr[12],*f;
716
717 if (spare < 0) return; // no format -> no spare area:-)
718
719 len = formats[3];
720
721 if (spare == 0) // locate descriptor with maximum capacity
722 { unsigned int max,cap;
723 int j;
724
725 i = 0;
726 for (max=0,j=8;j<len;j+=8)
727 { f = formats+4+j;
728 if ((f[4]>>2) == 0x32)
729 { cap = f[0]<<24|f[1]<<16|f[2]<<8|f[3];
730 if (max < cap) max=cap,i=j;
731 }
732 }
733 if (i==0)
734 fprintf (stderr,":-( can't locate format 0x32 descriptor\n"),
735 exit (FATAL_START(errno=EMEDIUMTYPE));
736 }
737 else
738 i = 8; // grab default descriptor
739
740 memset (descr,0,sizeof(descr));
741 descr[1]=0x02; // "IMMED" flag
742 descr[3]=0x08; // "Descriptor Lenght" (LSB)
743 memcpy (descr+4,formats+4+i,5);
744 descr[4+4]&=~3; // ensure "Format Subtype" is set to SRM+POW
745
746 f = descr+4;
747 fprintf (stderr,"%s: pre-formatting blank BD-R for %.1fGB...\n",
748 ioctl_device,(f[0]<<24|f[1]<<16|f[2]<<8|f[3])*2048.0/1e9);
749
750 cmd[0] = 0x04; // FORMAT UNIT
751 cmd[1] = 0x11; // "FmtData" and "Format Code"
752 cmd[5] = 0;
753 if ((err=cmd.transport(WRITE,descr,sizeof(descr))))
754 sperror ("FORMAT UNIT",err),
755 exit (FATAL_START(errno));
756
757 wait_for_unit (cmd);
758
759 bdr_plus_pow = 1;
760
761 cmd[0] = 0x35; // FLUSH CACHE
762 cmd[9] = 0;
763 cmd.transport();
764 }
765
bd_re_format(Scsi_Command & cmd)766 static void bd_re_format (Scsi_Command &cmd)
767 { int err,i,len;
768 unsigned char descr[12],*f;
769
770 len = formats[3];
771
772 if (spare == 0) // locate descriptor with maximum capacity
773 { unsigned int max,cap;
774 int j;
775
776 i = 0;
777 for (max=0,j=8;j<len;j+=8)
778 { f = formats+4+j;
779 if ((f[4]>>2) == 0x30)
780 { cap = f[0]<<24|f[1]<<16|f[2]<<8|f[3];
781 if (max < cap) max=cap,i=j;
782 }
783 }
784 if (i==0)
785 fprintf (stderr,":-( can't locate format 0x30 descriptor\n"),
786 exit (FATAL_START(errno=EMEDIUMTYPE));
787 }
788 else if (spare < 0) // locate descriptor 0x31
789 { for (i=8;i<len;i+=8)
790 if ((formats[4+i+4]>>2) == 0x31) break;
791 if (i==len)
792 fprintf (stderr,":-( can't locate format 0x31 descriptor\n"),
793 exit (FATAL_START(errno=EMEDIUMTYPE));
794 }
795 else
796 i = 8; // grab default descriptor
797
798 memset (descr,0,sizeof(descr));
799 descr[1]=0x02; // "IMMED" flag
800 descr[3]=0x08; // "Descriptor Lenght" (LSB)
801 memcpy (descr+4,formats+4+i,5);
802
803 f = descr+4;
804 fprintf (stderr,"%s: pre-formatting blank BD-RE for %.1fGB...\n",
805 ioctl_device,(f[0]<<24|f[1]<<16|f[2]<<8|f[3])*2048.0/1e9);
806
807 cmd[0] = 0x04; // FORMAT UNIT
808 cmd[1] = 0x11; // "FmtData" and "Format Code"
809 cmd[5] = 0;
810 if ((err=cmd.transport(WRITE,descr,sizeof(descr))))
811 sperror ("FORMAT UNIT",err),
812 exit(FATAL_START(errno));
813
814 wait_for_unit (cmd);
815
816 cmd[0] = 0x35; // FLUSH CACHE
817 cmd[9] = 0;
818 cmd.transport();
819 }
820
plus_rw_format(Scsi_Command & cmd)821 static void plus_rw_format (Scsi_Command &cmd)
822 { int err,i,len;
823 unsigned char descr[12];
824
825 if ((formats[4+4]&3) == 1) // Unformatted media
826 { fprintf (stderr,"%s: pre-formatting blank DVD+RW...\n",ioctl_device);
827
828 for (i=8,len=formats[3];i<len;i+=8)
829 if ((formats [4+i+4]>>2) == 0x26) break;
830
831 if (i==len)
832 fprintf (stderr,":-( can't locate DVD+RW format descriptor\n"),
833 exit(FATAL_START(EMEDIUMTYPE));
834
835 memset (descr,0,sizeof(descr));
836 descr[1]=0x02; // "IMMED" flag
837 descr[3]=0x08; // "Descriptor Length" (LSB)
838 memcpy (descr+4,formats+4+i,4);
839 descr[8]=0x26<<2; // "Format type" 0x26
840
841 cmd[0] = 0x04; // FORMAT UNIT
842 cmd[1] = 0x11; // "FmtData" and "Format Code"
843 cmd[5] = 0;
844 if ((err=cmd.transport(WRITE,descr,sizeof(descr))))
845 sperror ("FORMAT UNIT",err),
846 exit(FATAL_START(errno));
847
848 wait_for_unit (cmd);
849
850 cmd[0] = 0x35; // FLUSH CACHE
851 cmd[9] = 0;
852 if ((err=cmd.transport()))
853 sperror ("FLUSH CACHE",err),
854 exit(FATAL_START(errno));
855 }
856 }
857
plus_rw_restart_format(Scsi_Command & cmd,off64_t size)858 static int plus_rw_restart_format (Scsi_Command &cmd, off64_t size)
859 { unsigned char descr[12];
860 unsigned int lead_out,blocks;
861 int err,i,len;
862
863 if (!dvd_compat && size!=0)
864 { blocks = (unsigned int)(size/2048);
865 blocks += 15, blocks &= ~15;
866
867 lead_out = 0;
868 lead_out |= formats[4+0], lead_out <<= 8;
869 lead_out |= formats[4+1], lead_out <<= 8;
870 lead_out |= formats[4+2], lead_out <<= 8;
871 lead_out |= formats[4+3];
872
873 if (blocks<=lead_out) // no need to resume format...
874 return 0;
875 }
876
877 fprintf (stderr,"%s: restarting DVD+RW format...\n",ioctl_device);
878
879 for (i=8,len=formats[3];i<len;i+=8)
880 if ((formats [4+i+4]>>2) == 0x26) break;
881
882 if (i==len)
883 fprintf (stderr,":-( can't locate DVD+RW format descriptor\n"),
884 exit(FATAL_START(EMEDIUMTYPE));
885
886 memset (descr,0,sizeof(descr));
887 descr[1]=0x02; // "IMMED" flag
888 descr[3]=0x08; // "Descriptor Length" (LSB)
889 #if 1
890 memcpy (descr+4,formats+4+i,4);
891 #else
892 memset (descr+4,-1,4);
893 #endif
894 descr[8]=0x26<<2; // "Format type" 0x26
895 descr[11]=1; // "Restart Format"
896
897 cmd[0] = 0x04; // FORMAT UNIT
898 cmd[1] = 0x11; // "FmtData" and "Format Code"
899 cmd[5] = 0;
900 if ((err=cmd.transport(WRITE,descr,sizeof(descr))))
901 { sperror ("RESTART FORMAT",err);
902 return 1;
903 }
904
905 wait_for_unit(cmd);
906
907 return 0;
908 }
909
910 extern "C"
plusminus_r_C_parm(void * fd,char * C_parm)911 int plusminus_r_C_parm (void *fd,char *C_parm)
912 { unsigned int next_session, prev_session,err;
913 Scsi_Command cmd(fd);
914 unsigned char buf[36];
915
916 if ((disc_info[2]&3) != 1)
917 fprintf (stderr,":-( media is not appendable\n"),
918 exit(FATAL_START(EMEDIUMTYPE));
919
920 // allow to resume even --v-- incomplete sessions //
921 if (((disc_info[2]>>2)&3) > 1)
922 fprintf (stderr,":-( last session is not empty\n"),
923 exit(FATAL_START(EMEDIUMTYPE));
924
925 if (mmc_profile==0x41 && bdr_plus_pow)
926 next_track = disc_info[6]|disc_info[11]<<8;
927 else
928 next_track = disc_info[5]|disc_info[10]<<8;
929
930 #if defined(__APPLE__) && defined(__MACH__)
931 err = MMCIO(fd,ReadTrackInformation,1,next_track,buf,sizeof(buf));
932 #else
933 cmd[0] = 0x52; // READ TRACK INFORMATION
934 cmd[1] = 1;
935 cmd[4] = next_track>>8;
936 cmd[5] = next_track; // ask for last track
937 cmd[8] = sizeof(buf);
938 cmd[9] = 0;
939 err = cmd.transport (READ,buf,sizeof(buf));
940 #endif
941 if (err)
942 { sperror ("READ TRACK INFORMATION",err);
943 if (ASC(err)==0x24) // hp dvd200i returns 24 if media is full
944 fprintf (stderr,":-( media must be full already\n");
945 exit (FATAL_START(errno));
946 }
947
948 if (mmc_profile==0x41 && bdr_plus_pow && buf[7]&1) // NWA_V
949 { next_session = buf[12]<<24;
950 next_session |= buf[13]<<16;
951 next_session |= buf[14]<<8;
952 next_session |= buf[15];
953 }
954 else
955 { next_session = buf[8]<<24; // Track Start Address
956 next_session |= buf[9]<<16;
957 next_session |= buf[10]<<8;
958 next_session |= buf[11];
959 }
960
961 if (mmc_profile==0x41 && bdr_plus_pow)
962 prev_session=0;
963 else
964 { //
965 // All manuals say the data is fabricated, presumably implying
966 // that one should use another command. But we stick to this one
967 // because kernel uses this very command to mount multi-session
968 // discs.
969 //
970 #if defined(__APPLE__) && defined(__MACH__)
971 err = MMCIO(fd,ReadTableOfContents,0,1,0,buf,12);
972 #else
973 cmd[0] = 0x43; // READ TOC
974 cmd[2] = 1; // "Session info"
975 cmd[8] = 12;
976 cmd[9] = 0;
977 err = cmd.transport (READ,buf,12);
978 #endif
979 if (err)
980 sperror ("READ SESSION INFO",err),
981 exit (FATAL_START(errno));
982
983 prev_session = buf[8]<<24;
984 prev_session |= buf[9]<<16;
985 prev_session |= buf[10]<<8;
986 prev_session |= buf[11];
987 }
988
989 sprintf (C_parm,"%d,%d",prev_session+16,next_session);
990
991 return next_session;
992 }
993
pull_page2A(Scsi_Command & cmd)994 static unsigned char *pull_page2A (Scsi_Command &cmd)
995 { unsigned char *page2A,header[12];
996 unsigned int len,bdlen;
997 int err;
998
999 cmd[0] = 0x5A; // MODE SENSE
1000 cmd[1] = 0x08; // "Disable Block Descriptors"
1001 cmd[2] = 0x2A; // "Capabilities and Mechanical Status"
1002 cmd[8] = sizeof(header); // header only to start with
1003 cmd[9] = 0;
1004 if ((err=cmd.transport(READ,header,sizeof(header))))
1005 sperror ("MODE SENSE#2A",err), exit(FATAL_START(errno));
1006
1007 len = (header[0]<<8|header[1])+2;
1008 bdlen = header[6]<<8|header[7];
1009
1010 if (bdlen) // should never happen as we set "DBD" above
1011 { if (len < (8+bdlen+30))
1012 fprintf (stderr,":-( LUN is impossible to bear with...\n"),
1013 exit(FATAL_START(EINVAL));
1014 }
1015 else if (len < (8+2+(unsigned int)header[9]))// SANYO does this.
1016 len = 8+2+header[9];
1017
1018 page2A = (unsigned char *)malloc(len);
1019 if (page2A == NULL)
1020 fprintf (stderr,":-( memory exhausted\n"), exit(FATAL_START(ENOMEM));
1021
1022 cmd[0] = 0x5A; // MODE SENSE
1023 cmd[1] = 0x08; // "Disable Block Descriptors"
1024 cmd[2] = 0x2A; // "Capabilities and Mechanical Status"
1025 cmd[7] = len>>8;
1026 cmd[8] = len; // real length this time
1027 cmd[9] = 0;
1028 if ((err=cmd.transport(READ,page2A,len)))
1029 sperror ("MODE SENSE#2A",err),
1030 exit(FATAL_START(errno));
1031
1032 len -= 2;
1033 if (len < ((unsigned int)page2A[0]<<8|page2A[1])) // paranoia:-)
1034 page2A[0] = len>>8, page2A[1] = len;
1035
1036 return page2A;
1037 }
1038
pull_velocity(Scsi_Command & cmd,unsigned char * d)1039 static int pull_velocity (Scsi_Command &cmd,unsigned char *d)
1040 { unsigned int len;
1041 int v,err;
1042 class autofree perf;
1043
1044 #if 0 // 8x AccessTek derivatives, such as OptoRite DD0405
1045 if ((d[4]&2) == 0) return -1;
1046 #endif
1047
1048 len = (d[0]<<24|d[1]<<16|d[2]<<8|d[3])-4;
1049 if (len%16) return -1;
1050 if (len==0) return -1; // LG GCA-4040N:-(
1051
1052 len += 8;
1053 if (len == (8+16))
1054 { velocity = d[8+ 4]<<24|d[8+ 5]<<16|d[8+ 6]<<8|d[8+ 7];
1055 v = d[8+12]<<24|d[8+13]<<16|d[8+14]<<8|d[8+15];
1056 if (v>velocity) velocity=v; // CAV?
1057 }
1058 else // ZCLV
1059 { unsigned int n = (len-8)/16;
1060 unsigned char *p;
1061
1062 perf = (unsigned char *)malloc (len);
1063 if (perf == NULL)
1064 fprintf (stderr,":-( memory exhausted\n"),
1065 exit(FATAL_START(ENOMEM));
1066
1067 cmd[0]=0xAC; // GET PERFORMANCE
1068 cmd[1]=4; // ask for "Overall Write Performance"
1069 cmd[8]=n>>8;
1070 cmd[9]=n; // real number of descriptors
1071 cmd[10]=0; // ask for descriptor in effect
1072 cmd[11]=0;
1073 if ((err=cmd.transport(READ,perf,len)))
1074 sperror ("GET CURRENT PERFORMANCE",err),
1075 exit (FATAL_START(errno));
1076
1077 // Pick the highest speed...
1078 for (p=perf+8,len-=8;len;p+=16,len-=16)
1079 { v=p[ 4]<<24|p[ 5]<<16|p[ 6]<<8|p[ 7];
1080 if (v > velocity) velocity = v;
1081 v=p[12]<<24|p[13]<<16|p[14]<<8|p[15];
1082 if (v > velocity) velocity = v; // ZCAV?
1083 }
1084 }
1085
1086 return 0;
1087 }
1088
set_speed_B6h(Scsi_Command & cmd,unsigned int dvdplus,unsigned char * page2A)1089 static int set_speed_B6h (Scsi_Command &cmd,unsigned int dvdplus,
1090 unsigned char *page2A)
1091 { unsigned int len;
1092 int err;
1093 unsigned char d[8+16];
1094 class autofree perf;
1095
1096 cmd[0]=0xAC; // GET PERFORMACE
1097 cmd[9]=1; // start with one descriptor
1098 cmd[10]=0x3; // ask for "Write Speed Descriptor"
1099 cmd[11]=0;
1100 if ((err=cmd.transport(READ,d,sizeof(d))))
1101 { sperror ("GET PERFORMANCE",err);
1102 fprintf (stderr,":-( falling down to SET CD SPEED\n");
1103 return -1;
1104 }
1105
1106 len = (d[0]<<24|d[1]<<16|d[2]<<8|d[3])-4;
1107
1108 if (len%16) // insane length
1109 { fprintf (stderr,":-( GET PERFORMANCE: insane Performance Data Length\n");
1110 return -1;
1111 }
1112
1113 perf = (unsigned char *)malloc(len+=8);
1114 if (perf == NULL)
1115 fprintf (stderr,":-( memory exhausted\n"),
1116 exit(FATAL_START(ENOMEM));
1117
1118 if (len == sizeof(d))
1119 memcpy (perf,d,sizeof(d));
1120 else
1121 { unsigned int n=(len-8)/16;
1122
1123 cmd[0]=0xAC; // GET PERFORMANCE
1124 cmd[8]=n>>8;
1125 cmd[9]=n; // real number of descriptors
1126 cmd[10]=0x3; // ask for "Write Speed Descriptor"
1127 cmd[11]=0;
1128 if ((err=cmd.transport(READ,perf,len)))
1129 sperror ("GET PERFORMANCE",err),
1130 exit (FATAL_START(errno));
1131 }
1132
1133 int targetv=0,errp=0;
1134 do {
1135 memset (d,0,sizeof(d));
1136 cmd[0]=0xAC; // GET PERFORMANCE
1137 cmd[1]=4; // ask for "Overall Write performance"
1138 cmd[9]=1;
1139 cmd[10]=0; // ask for descriptor in effect
1140 cmd[11]=0;
1141 if (errp || (errp=cmd.transport(READ,d,sizeof(d))))
1142 #if 0
1143 sperror ("GET CURRENT PERFORMANCE",errp),
1144 exit (FATAL_START(errno)); // well, if it passed above, we
1145 // expect it to pass this too...
1146 #else // Pioneer doesn't report current speed through GET PERFORMANCE:-(
1147 { emulated_err:
1148
1149 if (page2A == NULL) return -1;
1150
1151 unsigned int plen,hlen;
1152
1153 plen = (page2A[0]<<8|page2A[1]) + 2;
1154 hlen = 8 + (page2A[6]<<8|page2A[7]);
1155
1156 unsigned char * const p = page2A + hlen;
1157
1158 if (plen<(hlen+32) || p[1]<(32-2))
1159 return -1; // well, SET CD SPEED wouldn't work...
1160
1161 velocity = p[28]<<8|p[29];
1162 }
1163 #endif
1164 else if ((errp = pull_velocity (cmd,d)) < 0)
1165 goto emulated_err;
1166
1167 if (speed_factor != 0.0)
1168 { int i,j=len-8,v,v0,v1,minv,closesti,closestv=0;
1169 unsigned char *wsdp=perf+8;
1170
1171 for (minv=0x7fffffff,i=0;i<j;i+=16)
1172 { v=wsdp[i+12]<<24|wsdp[i+13]<<16|wsdp[i+14]<<8|wsdp[i+15];
1173 if (v<minv) minv=v;
1174 } // minv will be treated as 1x
1175
1176 // New generation units offer minimum velocities other than 1x
1177 if (minv>(15*_1x)) speed_factor /= 16.0;
1178 else if (minv>(11*_1x)) speed_factor /= 12.0;
1179 else if (minv>(7*_1x)) speed_factor /= 8.0;
1180 else if (minv>(5*_1x)) speed_factor /= 6.0;
1181 else if (minv>(3*_1x)) speed_factor /= 4.0;
1182 else if (dvdplus && minv>(2*DVD_1X))
1183 // 2.4x is like 1x for DVD+, but it turned out that there're
1184 // units, most notably "DVDRW IDE1004," burning DVD+ at
1185 // lower speed, so I have to watch out for it...
1186 speed_factor /= 2.4;
1187 else if (minv>=(2*_1x))
1188 speed_factor /= 2.0;
1189
1190 v0=(int)(speed_factor*minv + 0.5);
1191 for (closesti=0,minv=0x7fffffff,i=0;i<j;i+=16)
1192 { v1=wsdp[i+12]<<24|wsdp[i+13]<<16|wsdp[i+14]<<8|wsdp[i+15];
1193 v=abs(v0-v1);
1194 if (v<minv) minv=v, closesti=i, closestv=v1;
1195 } // currenti is index of descriptor with *closest* velocity
1196
1197 targetv=closestv;
1198 speed_factor=0.0;
1199
1200 if (velocity==targetv)
1201 break; // already in shape, nothing to do...
1202
1203 unsigned char pd[28];
1204
1205 memset (pd,0,sizeof(pd)); // setup "Performance Descriptor"
1206
1207 pd[0]=*(wsdp+closesti); // copy "WRC" and other flags
1208 #if 0
1209 memset(pd+8,0xFF,4);
1210 #else // I might have to copy the value from current descriptor...
1211 unsigned int cap=get_2k_capacity(cmd)-1;
1212
1213 pd[8]=cap>>24;
1214 pd[9]=cap>>16;
1215 pd[10]=cap>>8;
1216 pd[11]=cap;
1217 #endif
1218 memcpy(pd+12,wsdp+closesti+8,4); // copy "Read Speed"
1219 memcpy(pd+20,wsdp+closesti+12,4); // copy "Write Speed"
1220 pd[18]=pd[26]=1000>>8; // set both "Read Time" and
1221 pd[19]=pd[27]=1000&0xFF; // "Write Time" to 1000ms
1222
1223 cmd[0]=0xB6; // SET STREAMING
1224 cmd[10]=sizeof(pd);
1225 cmd[11]=0;
1226 if ((err=cmd.transport (WRITE,pd,sizeof(pd))))
1227 sperror ("SET STREAMING",err),
1228 exit (FATAL_START(errno));
1229
1230 // I pull the Page 2A in either case, because unit might
1231 // have provided irrelevant information (Plextor). Not to
1232 // mention cases when it simply failed to reply to GET
1233 // CURRENT PERFORMANCE (Pioneer, LG).
1234
1235 unsigned int plen = (page2A[0]<<8|page2A[1]) + 2;
1236
1237 cmd[0] = 0x5A; // MODE SENSE
1238 cmd[1] = 0x08; // "Disable Block Descriptors"
1239 cmd[2] = 0x2A; // "Capabilities and Mechanical Status"
1240 cmd[7] = plen>>8;
1241 cmd[8] = plen; // real length this time
1242 cmd[9] = 0;
1243 if ((err=cmd.transport(READ,page2A,plen)))
1244 sperror ("MODE SENSE#2A",err),
1245 exit(FATAL_START(errno));
1246 }
1247 else if (targetv)
1248 { if (targetv!=velocity)
1249 { if (errp==0) // check Page 2A for speed then...
1250 { errp=-1; continue; }
1251 if (velocity==0 || velocity>=_1x)
1252 { fprintf(stderr,":-? Failed to change write speed: %d->%d\n",
1253 (int)velocity,targetv);
1254 if (velocity<targetv) velocity=targetv;
1255 }
1256 else
1257 { fprintf(stderr,":-( Failed to change write speed: %d->%d\n",
1258 (int)velocity,targetv);
1259 exit (FATAL_START(EINVAL));
1260 }
1261 }
1262 break;
1263 }
1264 } while (targetv);
1265
1266 return targetv;
1267 }
1268
set_speed_BBh(Scsi_Command & cmd,unsigned char * page2A)1269 static int set_speed_BBh (Scsi_Command &cmd,unsigned char *page2A)
1270 { unsigned int plen,hlen;
1271 int err;
1272
1273 plen = (page2A[0]<<8|page2A[1]) + 2;
1274 hlen = 8 + (page2A[6]<<8|page2A[7]);
1275
1276 unsigned char * const p = page2A + hlen;
1277
1278 if (plen<(hlen+32) || p[1]<(32-2))
1279 return -1;
1280
1281 int targetv=0;
1282 do {
1283 velocity = p[28]<<8|p[29];
1284
1285 if (speed_factor != 0.0)
1286 { int i,j,v,v0,v1,minv,closesti,closestv=0;
1287 unsigned char *wsdp=p+32;
1288
1289 j=(p[30]<<8|p[31])*4;
1290 for (minv=0x7fffffff,i=0;i<j;i+=4)
1291 { v=wsdp[i+2]<<8|wsdp[i+3];
1292 if (v<minv) minv=v;
1293 } // minv will be treated as 1x
1294
1295 v0=(int)(speed_factor*minv + 0.5);
1296 for (closesti=0,minv=0x7fffffff,i=0;i<j;i+=4)
1297 { v1=wsdp[i+2]<<8|wsdp[i+3];
1298 v=abs(v0-v1);
1299 if (v<minv) minv=v, closesti=i, closestv=v1;
1300 } // currenti is index of descriptor with *closest* velocity
1301
1302 targetv=closestv;
1303 speed_factor=0.0;
1304
1305 if (velocity==targetv)
1306 break; // already in shape, nothing to do...
1307
1308 cmd[0]=0xBB; // SET CD SPEED
1309 cmd[1]=wsdp[closesti+1]; // Rotation Control
1310 cmd[2]=cmd[3]=0xff; // Read Speed
1311 cmd[4]=wsdp[closesti+2]; // Write Speed
1312 cmd[5]=wsdp[closesti+3];
1313 cmd[11]=0;
1314 if ((err=cmd.transport()))
1315 sperror ("SET CD SPEED",err),
1316 exit (FATAL_START(errno));
1317
1318 cmd[0] = 0x5A; // MODE SENSE
1319 cmd[1] = 0x08; // "Disable Block Descriptors"
1320 cmd[2] = 0x2A; // "Capabilities and Mechanical Status"
1321 cmd[7] = plen>>8;
1322 cmd[8] = plen; // real length this time
1323 cmd[9] = 0;
1324 if ((err=cmd.transport(READ,page2A,plen)))
1325 sperror ("MODE SENSE#2A",err),
1326 exit(FATAL_START(errno));
1327 }
1328 else if (targetv)
1329 { if (targetv!=velocity)
1330 fprintf (stderr,":-( Failed to change write speed: %d->%d\n",
1331 (int)velocity,targetv),
1332 exit (FATAL_START(EINVAL));
1333 break;
1334 }
1335 } while (targetv);
1336
1337 return targetv;
1338 }
1339
plusminus_pages_setup(Scsi_Command & cmd,int profile)1340 static int plusminus_pages_setup (Scsi_Command &cmd,int profile)
1341 { unsigned int plen,hlen,dvddash=0,dvdplus=0;
1342 unsigned char header[16],p32;
1343 int err;
1344 class autofree page2A;
1345
1346 switch (profile)
1347 { case 0x1A: // DVD+RW
1348 p32 = 0;
1349 dvdplus=1;
1350 break;
1351 case 0x1B: // DVD+R
1352 //
1353 // Even though MMC-4 draft explicitely exempts DVD+RW/+R media
1354 // from those being affected by Page 05h settings, some
1355 // firmwares apparently pay attention to Multi-session flag
1356 // when finalizing DVD+R media. Well, we probably can't blame
1357 // vendors as specification is still a work in progress, not to
1358 // mention that it was published after DVD+R was introduced to
1359 // the market.
1360 //
1361 p32 = dvd_compat?0x02:0xC0;
1362 dvdplus=1;
1363 break;
1364 case 0x13: // DVD-RW Restricted Overwrite
1365 p32 = 0xC0; // NB! Test Write in not option here
1366 dvddash = 1;
1367 break;
1368 case 0x11: // DVD-R Sequential
1369 case 0x14: // DVD-RW Sequential
1370 case 0x15: // DVD-R Dual Layer Sequential
1371 p32 = 0xC0;
1372 if (next_track==1) do
1373 { if (dvd_compat >= (profile==0x14?2:256))
1374 { is_dao = 1,
1375 fprintf (stderr,"%s: engaging DVD-%s DAO upon user request...\n",
1376 ioctl_device,profile==0x14?"RW":"R");
1377 break;
1378 }
1379
1380 // Try to figure out if we have to go for DAO...
1381 cmd[0] = 0x46; // GET CONFIGURATION
1382 cmd[1] = 2; // ask for the only feature...
1383 cmd[3] = 0x21; // the "Incremental Streaming Writable" one
1384 cmd[8] = 16; // The feature should be there, right?
1385 cmd[9] = 0;
1386 if ((err=cmd.transport (READ,header,16)))
1387 sperror ("GET FEATURE 21h",err),
1388 exit(FATAL_START(errno));
1389
1390 hlen = header[0]<<24|header[1]<<16|header[2]<<8|header[3];
1391 // See if Feature 21h is "current," if not, engage DAO...
1392 if (hlen>=12 && (header[8+2]&1)==0)
1393 { is_dao = dvd_compat = 1;
1394 fprintf (stderr,"%s: FEATURE 21h is not on, engaging DAO...\n",
1395 ioctl_device);
1396 break;
1397 }
1398 } while (0);
1399
1400 if (is_dao) p32 |=2; // DAO
1401
1402 if (profile==0x15 || // DVD-R DL Seq has no notion of multi-session
1403 dvd_compat) p32 &= 0x3F; // Single-session
1404
1405 if (test_write)
1406 p32 |= 0x10; // Test Write for debugging purposes
1407
1408 dvddash=1;
1409 break;
1410 case 0x16: // DVD-R Dual Layer Jump
1411 p32 = 0xC0;
1412 p32 |= 4; // Jump
1413 if (test_write)
1414 p32 |= 0x10; // Test Write for debugging purposes
1415
1416 dvddash=1;
1417 break;
1418 default:
1419 p32 = 0;
1420 break;
1421 }
1422
1423 if (dvddash || p32) page05_setup (cmd,profile,p32);
1424
1425 page2A = pull_page2A (cmd);
1426
1427 plen = (page2A[0]<<8|page2A[1]) + 2;
1428 hlen = 8 + (page2A[6]<<8|page2A[7]);
1429
1430 unsigned char * const p = page2A + hlen;
1431
1432 if (plen<(hlen+14) || p[1]<(14-2)) // no "Buffer Size Supported"
1433 buf_size = 512; // bogus value
1434 else
1435 buf_size = (p[12]<<8|p[13]);
1436 if (buf_size<512) // bogus value
1437 buf_size = 512;
1438
1439 // GET PERFORMANCE/SET STREAMING are listed as mandatory, so that
1440 // this is actually the most likely path...
1441 if (set_speed_B6h (cmd,dvdplus,page2A) >= 0)
1442 goto opc;
1443
1444 if (plen<(hlen+30) || p[1]<(30-2)) // no "Current Write Speed" present
1445 { if (dvddash)
1446 { fprintf (stderr,":-( \"Current Write Speed\" descriptor "
1447 "is not present, faking 1x...\n"),
1448 velocity = _1x;
1449 speed_factor = 0.0;
1450 }
1451 else
1452 velocity = 0;
1453 }
1454 else do
1455 { velocity = p[28]<<8|p[29];
1456
1457 // Some units, most notably NEC and derivatives, were observed
1458 // to report CD-R descriptors...
1459 if (velocity < DVD_1X) // must be bogus
1460 { velocity=0;
1461 break;
1462 }
1463
1464 if (plen<(hlen+32) || p[1]<(32-2)) // no write descriptors
1465 break;
1466
1467 int n = p[30]<<8|p[31],minv=1<<16;
1468 unsigned char *p_= p+32;
1469 for (;n--;p_+=4)
1470 { int v=p_[2]<<8|p_[3];
1471 if (v==0) continue; // Lite-On returns zeros here...
1472 if (v<_1x) // must be bogus
1473 velocity=0;
1474 if (v < minv)
1475 minv = v;
1476 }
1477 if (dvdplus && minv>2*_1x)
1478 // See corresponding comment in set_speed_B6h()
1479 speed_factor /= 2.4;
1480
1481 } while (0);
1482
1483 if (speed_factor != 0.0 &&
1484 (velocity==0 || set_speed_BBh (cmd,page2A)<0) )
1485 fprintf (stderr,":-( can't control writing velocity, "
1486 "-speed option is ignored\n");
1487 opc:
1488
1489 if (!dvddash || test_write || no_opc) return 0;
1490
1491 // See if OPC is required...
1492 cmd[0] = 0x51; // READ DISC INFORMATION
1493 cmd[8] = 8;
1494 cmd[9] = 0;
1495 if ((err=cmd.transport (READ,header,8)))
1496 sperror ("READ DISC INFORMATION",err),
1497 exit(FATAL_START(errno));
1498
1499 if ((header[0]<<8|header[1]) <= 0x20)
1500 { cmd[0] = 0x54; // SEND OPC INFORMATION
1501 cmd[1] = 1; // "Perform OPC"
1502 cmd[9] = 0;
1503 cmd.timeout(120); // NEC units can be slooo...w
1504 if ((err=cmd.transport())) do
1505 { if (err==0x17301) // "POWER CALIBRATION AREA ALMOST FULL"
1506 { fprintf (stderr,":-! WARNING: Power Calibration Area "
1507 "is almost full\n");
1508 break;
1509 }
1510 sperror ("PERFORM OPC",err);
1511 if ((err&0x0FF00)==0x07300 && (err&0xF0000)!=0x10000)
1512 exit(FATAL_START(errno));
1513 /*
1514 * The rest of errors are ignored, most notably observed:
1515 * 0x52000, "INVALID COMMAND" Panasonic LD-F321
1516 * 0x52700, "WRITE PROTECTED" Plextor PX-712A
1517 * 0x52C00, "COMMAND SEQUENCE ERROR" Plextor PX-716UF
1518 * 0x53002, "MEDIA NOT SUPPORTED" Toshiba TS-H542A
1519 */
1520 } while (0);
1521 }
1522
1523 handle_events(cmd);
1524
1525 return 0;
1526 }
1527
minus_rw_quickgrow(Scsi_Command & cmd,off64_t size)1528 static int minus_rw_quickgrow (Scsi_Command &cmd,off64_t size)
1529 { unsigned char format[12];
1530 unsigned int lead_out,blocks,type;
1531 int i,len,err;
1532
1533 type = formats[4+4]&3;
1534
1535 if (type==2 && size!=0)
1536 { blocks = (unsigned int)(size/2048);
1537 blocks += 15, blocks &= ~15;
1538
1539 lead_out = 0;
1540 lead_out |= formats[4+0], lead_out <<= 8;
1541 lead_out |= formats[4+1], lead_out <<= 8;
1542 lead_out |= formats[4+2], lead_out <<= 8;
1543 lead_out |= formats[4+3];
1544
1545 if (blocks<=lead_out) // no need to grow the session...
1546 return 0;
1547 }
1548
1549 // look for Quick Grow descriptor...
1550 for (i=8,len=formats[3];i<len;i+=8)
1551 if ((formats [4+i+4]>>2) == 0x13) break;
1552
1553 if (i==len) // no Quick Grow descriptor
1554 { if (type != 2)
1555 quickgrown=1; // in reality quick formatted...
1556 return 0;
1557 }
1558 else
1559 { blocks = 0;
1560 blocks |= formats[i+0], blocks <<= 8;
1561 blocks |= formats[i+1], blocks <<= 8;
1562 blocks |= formats[i+2], blocks <<= 8;
1563 blocks |= formats[i+3];
1564 if (type==2 && blocks==0) // nowhere no grow...
1565 return 0;
1566 }
1567
1568 quickgrown=1;
1569 fprintf (stderr,"%s: \"Quick Grow\" session...\n",ioctl_device);
1570
1571 memset (format,0,sizeof(format));
1572 format [1] = 2; // "IMMED"
1573 format [3] = 8; // "Length"
1574 format [8] = 0x13<<2; // "Quick Grow"
1575 format [11] = 16;
1576
1577 cmd[0] = 0x4; // FORMAT UNIT
1578 cmd[1] = 0x11;
1579 cmd[5] = 0;
1580 if ((err=cmd.transport (WRITE,format,sizeof(format))))
1581 { sperror ("QUICK GROW",err);
1582 return 1;
1583 }
1584
1585 return wait_for_unit (cmd);
1586 }
1587
minus_r_reserve_track(Scsi_Command & cmd,off64_t size)1588 static int minus_r_reserve_track (Scsi_Command &cmd,off64_t size)
1589 { int err;
1590 unsigned int blocks;
1591
1592 blocks = (unsigned int)(size/2048);
1593 if (is_dao) dao_blocks = blocks;
1594 else blocks += 15, blocks &= ~15;
1595
1596 fprintf (stderr,"%s: reserving %u blocks",ioctl_device,blocks);
1597 if (is_dao && blocks<380000)
1598 fprintf (stderr,"\b, warning for short DAO recording"),
1599 poll (NULL,0,5000);
1600 fprintf (stderr,"\n");
1601
1602
1603 cmd[0] = 0x53; // RESERVE TRACK
1604 cmd[5] = blocks>>24;
1605 cmd[6] = blocks>>16;
1606 cmd[7] = blocks>>8;
1607 cmd[8] = blocks;
1608 cmd[9] = 0;
1609 if ((err=cmd.transport ()))
1610 { sperror ("RESERVE TRACK",err);
1611 return 1;
1612 }
1613
1614 return 0;
1615 }
1616
plus_r_dl_split(Scsi_Command & cmd,off64_t size)1617 static void plus_r_dl_split (Scsi_Command &cmd,off64_t size)
1618 { int err;
1619 unsigned int blocks,split;
1620 unsigned char dvd_20[4+8];
1621
1622 cmd[0] = 0xAD; // READ DVD STRUCTURE
1623 cmd[7] = 0x20; // "DVD+R Double Layer Boundary Information"
1624 cmd[9] = sizeof(dvd_20);
1625 cmd[11] = 0;
1626 if ((err=cmd.transport(READ,dvd_20,sizeof(dvd_20))))
1627 sperror ("READ DVD+R DL BOUNDARY INFORMATION",err),
1628 exit (FATAL_START(errno));
1629
1630 if ((dvd_20[0]<<8|dvd_20[1]) < 10)
1631 fprintf (stderr,":-( insane DVD+R DL BI structure length\n"),
1632 exit (FATAL_START(EINVAL));
1633
1634 if (dvd_20[4]&0x80)
1635 { fprintf (stderr,":-? L0 Data Zone Capacity is set already\n");
1636 return;
1637 }
1638
1639 split = dvd_20[8]<<24|dvd_20[9]<<16|dvd_20[10]<<8|dvd_20[11];
1640
1641 blocks = (unsigned int)(size/2048);
1642 blocks += 15, blocks &= ~15;
1643
1644 if (blocks <= split)
1645 fprintf (stderr,":-( more than 50%% of space will be *wasted*!\n"
1646 " use single layer media for this recording\n"),
1647 exit (FATAL_START(EMEDIUMTYPE));
1648
1649 blocks /= 16;
1650 blocks += 1;
1651 blocks /= 2;
1652 blocks *= 16;
1653
1654 fprintf (stderr,"%s: splitting layers at %u blocks\n",
1655 ioctl_device,blocks);
1656
1657 memset (dvd_20,0,sizeof(dvd_20));
1658 dvd_20[1] = sizeof(dvd_20)-2;
1659 dvd_20[8] = blocks>>24;
1660 dvd_20[9] = blocks>>16;
1661 dvd_20[10] = blocks>>8;
1662 dvd_20[11] = blocks;
1663
1664 cmd[0] = 0xBF; // SEND DVD STRUCTURE
1665 cmd[7] = 0x20; // "DVD+R Double Layer Recording Information"
1666 cmd[9] = sizeof(dvd_20);
1667 cmd[11] = 0;
1668 cmd.timeout(180); // Lite-on seems to fire off calibration here
1669 if ((err=cmd.transport(WRITE,dvd_20,sizeof(dvd_20))))
1670 sperror ("SEND DVD+R DOUBLE LAYER RECORDING INFORMATION",err),
1671 exit (FATAL_START(errno));
1672
1673 }
1674
flush_cache(Scsi_Command & cmd,int even_sync=1)1675 static int flush_cache (Scsi_Command &cmd, int even_sync=1)
1676 { int err;
1677
1678 cmd[0] = 0x35; // FLUSH CACHE
1679 cmd[1] = 0x02; // "IMMED"
1680 cmd[9] = 0;
1681 if (!(err=cmd.transport()))
1682 wait_for_unit (cmd);
1683 else
1684 sperror ("FLUSH CACHE",err);
1685
1686 if (even_sync) // Pioneer apparently needs this,
1687 { // non-IMMED FLUSH that is...
1688 cmd[0] = 0x35; // FLUSH CACHE
1689 cmd[9] = 0;
1690 if (is_dao) cmd.timeout (15*60);
1691 if ((err=cmd.transport()))
1692 { sperror ("SYNCHRONOUS FLUSH CACHE",err);
1693 return err;
1694 }
1695 }
1696
1697 return 0;
1698 }
1699
1700 //
1701 // atexit/signal handlers
1702 //
1703 extern "C"
no_r_finalize()1704 void no_r_finalize ()
1705 { while (media_written)
1706 { Scsi_Command cmd(ioctl_handle);
1707
1708 fprintf (stderr,"%s: flushing cache\n",ioctl_device);
1709 if (flush_cache (cmd)) break;
1710
1711 pioneer_stop (cmd);
1712
1713 media_written = 0;
1714 errno = EINTR;
1715 }
1716 _exit (errno);
1717 }
1718
1719 extern "C"
plus_rw_finalize()1720 void plus_rw_finalize ()
1721 { int saved_errno = errno;
1722
1723 sigs_mask(SIGS_BLOCK);
1724 while (media_written)
1725 { Scsi_Command cmd(ioctl_handle);
1726 int err;
1727
1728 fprintf (stderr,"%s: flushing cache\n",ioctl_device);
1729 if (flush_cache (cmd)) break;
1730
1731 if (!dvd_compat)
1732 { fprintf (stderr,"%s: stopping de-icing\n",ioctl_device);
1733 cmd[0] = 0x5B; // CLOSE TRACK/SESSION
1734 cmd[1] = 0x01; // "IMMED"
1735 cmd[2] = 0; // "Stop De-Icing"
1736 cmd[9] = 0;
1737 if ((err=cmd.transport()))
1738 sperror ("STOP DE-ICING",err);
1739
1740 if (wait_for_unit (cmd)) break;
1741 }
1742
1743 fprintf (stderr,"%s: writing lead-out\n",ioctl_device);
1744 cmd[0] = 0x5B; // CLOSE TRACK/SESSION
1745 cmd[1] = 0x01; // "IMMED"
1746 cmd[2] = 0x02; // "Close session"
1747 cmd[9] = 0;
1748 if ((err=cmd.transport()))
1749 sperror ("CLOSE SESSION",err);
1750
1751 if (wait_for_unit (cmd)) break;
1752
1753 media_written = 0;
1754 next_wr_addr = 0;
1755
1756 if (do_reload && media_reload())
1757 perror (":-( unable to reload tray");// not actually reached
1758
1759 errno = saved_errno;
1760 }
1761 _exit (errno);
1762 }
1763
1764 extern "C"
bd_re_finalize()1765 void bd_re_finalize ()
1766 { int saved_errno = errno;
1767
1768 sigs_mask(SIGS_BLOCK);
1769 while (media_written)
1770 { Scsi_Command cmd(ioctl_handle);
1771
1772 fprintf (stderr,"%s: flushing cache\n",ioctl_device);
1773 if (flush_cache (cmd)) break;
1774
1775 media_written = 0;
1776 next_wr_addr = 0;
1777
1778 if (do_reload && media_reload())
1779 perror (":-( unable to reload tray");// not actually reached
1780
1781 errno = saved_errno;
1782 }
1783 _exit (errno);
1784 }
1785
1786 extern "C"
plus_r_finalize()1787 void plus_r_finalize ()
1788 { int saved_errno = errno;
1789
1790 sigs_mask(SIGS_BLOCK);
1791 while (media_written)
1792 { Scsi_Command cmd(ioctl_handle);
1793 int mode,err;
1794
1795 fprintf (stderr,"%s: flushing cache\n",ioctl_device);
1796 if (flush_cache(cmd)) break;
1797
1798 fprintf (stderr,"%s: closing track\n",ioctl_device);
1799 cmd[0] = 0x5B; // CLOSE TRACK/SESSION
1800 cmd[1] = 0x01; // "IMMED"
1801 cmd[2] = 0x01; // "Close Track"
1802 cmd[4] = next_track>>8;
1803 cmd[5] = next_track;
1804 cmd[9] = 0;
1805 if ((err=cmd.transport()))
1806 sperror ("CLOSE TRACK",err), saved_errno = errno;
1807
1808 if (wait_for_unit (cmd)) break;
1809
1810 if (dvd_compat)
1811 // HP dvd520n insists on "finalize with minimum radius"
1812 // with DVD+R DL ---------------vv
1813 mode = ((mmc_profile&0xFFFF)==0x2B)?0x05:0x06,
1814 fprintf (stderr,"%s: closing disc\n",ioctl_device);
1815 else
1816 mode = 0x02,
1817 fprintf (stderr,"%s: closing session\n",ioctl_device);
1818
1819 while (1) // Pioneer DVR-K04RA
1820 { cmd[0] = 0x5B; // CLOSE TRACK/SESSION
1821 cmd[1] = 0x01; // "IMMED"
1822 cmd[2] = mode; // "Close session"
1823 cmd[9] = 0;
1824 err = cmd.transport();
1825 if (err == 0x20407) // "OP IN PROGRESS"
1826 { poll (NULL,0,stdnap);
1827 continue;
1828 }
1829 else if (err)
1830 sperror (dvd_compat?"CLOSE DISC":"CLOSE SESSION",err),
1831 saved_errno = errno;
1832 break;
1833 }
1834
1835 if (wait_for_unit (cmd)) break;
1836
1837 media_written = 0;
1838
1839 if (do_reload && media_reload())
1840 perror (":-( unable to reload tray");// not actually reached
1841
1842 errno = saved_errno;
1843 }
1844 _exit (errno);
1845 }
1846
1847 extern "C"
minus_rw_finalize()1848 void minus_rw_finalize ()
1849 { int saved_errno = errno;
1850
1851 sigs_mask(SIGS_BLOCK);
1852 while (media_written)
1853 { Scsi_Command cmd(ioctl_handle);
1854 int err;
1855
1856 fprintf (stderr,"%s: flushing cache\n",ioctl_device);
1857 if (flush_cache(cmd)) break;
1858
1859 if (quickgrown)
1860 { fprintf (stderr,"%s: writing lead-out\n",ioctl_device);
1861 cmd[0] = 0x5B; // CLOSE TRACK/SESSION
1862 cmd[1] = 0x01; // "IMMED"
1863 cmd[2] = 0x02; // "Close Session"
1864 cmd[9] = 0;
1865 if ((err=cmd.transport()))
1866 sperror ("CLOSE SESSION",err), saved_errno = errno;
1867
1868 if (wait_for_unit (cmd)) break;
1869
1870 quickgrown=0;
1871 }
1872
1873 media_written = 0;
1874 next_wr_addr = 0;
1875
1876 if (do_reload)
1877 { if (media_reload())
1878 perror (":-( unable to reload tray");// not actually reached
1879 }
1880 else return; // Restricted Overwrite is just ugly!
1881
1882 errno = saved_errno;
1883 }
1884 _exit (errno);
1885 }
1886
1887 extern "C"
minus_r_finalize()1888 void minus_r_finalize ()
1889 { int saved_errno = errno;
1890
1891 sigs_mask(SIGS_BLOCK);
1892 while (media_written)
1893 { Scsi_Command cmd(ioctl_handle);
1894 int err;
1895
1896 fprintf (stderr,"%s: flushing cache\n",ioctl_device);
1897 if (flush_cache(cmd,!is_dao)) break;
1898
1899 if (!is_dao)
1900 { fprintf (stderr,"%s: updating RMA\n",ioctl_device);
1901 cmd[0] = 0x5B; // CLOSE TRACK/SESSION
1902 cmd[1] = 0x01; // "IMMED"
1903 cmd[2] = 0x01; // "Close Track"
1904 cmd[4] = next_track>>8;
1905 cmd[5] = next_track;
1906 cmd[9] = 0;
1907 if ((err=cmd.transport()))
1908 sperror ("CLOSE TRACK",err), saved_errno = errno;
1909
1910 if (wait_for_unit (cmd)) break;
1911
1912 fprintf (stderr,"%s: closing %s\n",ioctl_device,
1913 dvd_compat?"disc":"session");
1914
1915 while (1) // Pioneer DVR-K04RA
1916 { cmd[0] = 0x5B; // CLOSE TRACK/SESSION
1917 cmd[1] = 0x01; // "IMMED"
1918 cmd[2] = 0x02; // "Close Session"
1919 cmd[9] = 0;
1920 err = cmd.transport();
1921 if (err == 0x20407) // "OP IN PROGRESS"
1922 { poll (NULL,0,stdnap);
1923 continue;
1924 }
1925 else if (err)
1926 sperror (dvd_compat?"CLOSE DISC":"CLOSE SESSION",err),
1927 saved_errno = errno;
1928 break;
1929 }
1930
1931 if (wait_for_unit (cmd)) break;
1932 }
1933
1934 media_written = 0;
1935
1936 if (do_reload && media_reload())
1937 perror (":-( unable to reload tray");// not actually reached
1938
1939 errno = saved_errno;
1940 }
1941 _exit (errno);
1942 }
1943
1944 extern "C"
bd_r_finalize()1945 void bd_r_finalize ()
1946 { int saved_errno = errno;
1947
1948 sigs_mask(SIGS_BLOCK);
1949 while (media_written)
1950 { Scsi_Command cmd(ioctl_handle);
1951 int err;
1952
1953 fprintf (stderr,"%s: flushing cache\n",ioctl_device);
1954 if (flush_cache(cmd)) break;
1955
1956 fprintf (stderr,"%s: closing track\n",ioctl_device);
1957 cmd[0] = 0x5B; // CLOSE TRACK/SESSION
1958 cmd[1] = 0x01; // "IMMED"
1959 cmd[2] = 0x01; // "Close Track"
1960 cmd[4] = next_track>>8;
1961 cmd[5] = next_track;
1962 cmd[9] = 0;
1963 if ((err=cmd.transport()))
1964 sperror ("CLOSE TRACK",err), saved_errno = errno;
1965
1966 if (wait_for_unit (cmd)) break;
1967
1968 if (!bdr_plus_pow)
1969 { fprintf (stderr,"%s: closing session\n",ioctl_device);
1970 while (1) // Pioneer DVR-K04RA
1971 { cmd[0] = 0x5B; // CLOSE TRACK/SESSION
1972 cmd[1] = 0x01; // "IMMED"
1973 cmd[2] = 0x02; // "Close session"
1974 cmd[9] = 0;
1975 err = cmd.transport();
1976 if (err == 0x20407) // "OP IN PROGRESS"
1977 { poll (NULL,0,stdnap);
1978 continue;
1979 }
1980 else if (err)
1981 sperror ("CLOSE SESSION",err), saved_errno = errno;
1982 break;
1983 }
1984
1985 if (wait_for_unit (cmd)) break;
1986 }
1987
1988 media_written = 0;
1989
1990 if (do_reload && media_reload())
1991 perror (":-( unable to reload tray");// not actually reached
1992
1993 errno = saved_errno;
1994 }
1995 _exit (errno);
1996 }
1997
1998 extern "C"
ram_reload()1999 void ram_reload ()
2000 { int saved_errno = errno;
2001 sigs_mask(SIGS_BLOCK);
2002 if (media_written && do_reload) media_reload();
2003 _exit (saved_errno);
2004 }
2005
2006 //
2007 // poor_mans_setup takes care of a lot of things.
2008 // It's invoked right before first write and if necessary/applicable
2009 // prepares Page 05, reserves track, sets up atexit and signal handlers.
2010 //
2011
2012 typedef ssize_t (*pwrite64_t)(int,const void *,size_t,off64_t);
2013
2014 extern "C"
poor_mans_setup(void * fd,off64_t leadout)2015 pwrite64_t poor_mans_setup (void *fd,off64_t leadout)
2016 { Scsi_Command cmd(ioctl_handle=fd);
2017 int err,profile=mmc_profile&0xFFFF;
2018
2019 // We might have loaded media ourselves, in which case we
2020 // should lock the door...
2021 cmd[0] = 0x1E; // PREVENT/ALLOW MEDIA REMOVAL
2022 cmd[4] = 1; // "Prevent"
2023 cmd[5] = 0;
2024 if ((err=cmd.transport ()))
2025 sperror ("PREVENT MEDIA REMOVAL",err),
2026 exit (FATAL_START(errno));
2027
2028 handle_events(cmd);
2029
2030 // This actually belongs in get_mmc_profile, but the trouble
2031 // is that Mac OS X does not implement ReadCapacity method and
2032 // therefore we have to do it here, after we went exclusive...
2033 if (!(mmc_profile&0x10000)) // non-blank media
2034 { unsigned char c[8];
2035
2036 cmd[0] = 0x25; // READ CAPACITY
2037 cmd[9] = 0;
2038 if (!cmd.transport (READ,c,sizeof(c)))
2039 cap2kstart = c[0]<<24|c[1]<<16|c[2]<<8|c[3];
2040 }
2041
2042 switch (profile)
2043 { case 0x1A: // DVD+RW
2044 switch (disc_info[7]&3) // Background formatting
2045 { case 0: // blank
2046 plus_rw_format (cmd);
2047 break;
2048 case 1: // suspended
2049 plus_rw_restart_format (cmd,leadout);
2050 break;
2051 case 2: // in progress
2052 case 3: // complete
2053 break;
2054 }
2055
2056 plusminus_pages_setup (cmd,profile);
2057 atexit (plus_rw_finalize);
2058 atsignals (plus_rw_finalize);
2059 break;
2060 case 0x1B: // DVD+R
2061 case 0x2B: // DVD+R Double Layer
2062 plusminus_pages_setup(cmd,profile);
2063 if (profile==0x2B && next_track==1 && dvd_compat && leadout)
2064 plus_r_dl_split (cmd,leadout);
2065 atexit (plus_r_finalize);
2066 if (next_wr_addr)
2067 { atsignals (no_r_finalize);
2068 next_wr_addr=(unsigned int)-1;
2069 }
2070 else atsignals (plus_r_finalize);
2071 break;
2072 case 0x13: // DVD-RW Restricted Overwrite
2073 plusminus_pages_setup (cmd,profile);
2074 //
2075 // A side note. Quick Grow can't be performed earlier,
2076 // as then reading is not possible.
2077 //
2078 minus_rw_quickgrow (cmd,leadout);
2079 atexit (minus_rw_finalize);
2080 atsignals (minus_rw_finalize);
2081 break;
2082 case 0x11: // DVD-R Sequential
2083 case 0x14: // DVD-RW Sequential
2084 case 0x15: // DVD-R Dual Layer Sequential
2085 plusminus_pages_setup (cmd,profile);
2086 if ((profile==0x15) && leadout)
2087 { unsigned char dvd_10[4+16];
2088 unsigned int layer_size,data_size=(unsigned int)(leadout/2048);
2089
2090 cmd[0] = 0xAD; // READ DVD STRUCTURE
2091 cmd[7] = 0x10;
2092 cmd[9] = sizeof(dvd_10);
2093 cmd[11] = 0;
2094 if ((err=cmd.transport(READ,dvd_10,sizeof(dvd_10))))
2095 sperror("READ DVD STRUCTURE #10h",err),
2096 exit(FATAL_START(errno));
2097
2098 layer_size = dvd_10[4+13]<<16,
2099 layer_size |= dvd_10[4+14]<<8,
2100 layer_size |= dvd_10[4+15];
2101
2102 if (data_size <= layer_size)
2103 fprintf (stderr,":-( more than 50%% of space will be *wasted*!\n"
2104 " use single layer media for this recording\n"),
2105 exit(FATAL_START(EMEDIUMTYPE));
2106 }
2107 if (is_dao && leadout)
2108 minus_r_reserve_track(cmd,leadout);
2109 atexit (minus_r_finalize);
2110 if (next_wr_addr)
2111 { atsignals (no_r_finalize);
2112 next_wr_addr=(unsigned int)-1;
2113 }
2114 else atsignals (minus_r_finalize);
2115 break;
2116 case 0x12: // DVD-RAM
2117 // exclusively for speed settings...
2118 plusminus_pages_setup (cmd,profile);
2119 atexit (ram_reload);
2120 atsignals (ram_reload);
2121 break;
2122 case 0x41: // BD-R SRM
2123 if ((disc_info[2]&3) == 0) // blank
2124 bd_r_format (cmd);
2125 // exclusively for speed settings...
2126 plusminus_pages_setup (cmd,profile);
2127 atexit (bd_r_finalize);
2128 if (next_wr_addr)
2129 { atsignals (no_r_finalize);
2130 next_wr_addr=(unsigned int)-1;
2131 }
2132 else atsignals (bd_r_finalize);
2133 break;
2134 case 0x43: // BR-RE
2135 if ((disc_info[2]&3) == 0) // blank
2136 bd_re_format (cmd);
2137 // exclusively for speed settings...
2138 plusminus_pages_setup (cmd,profile);
2139 atexit(bd_re_finalize);
2140 atsignals(bd_re_finalize);
2141 break;
2142 case 0x42: // BD-R RRM is not supported yet...
2143 case 0x16: // DVD-R Dual Layer Jump not supported for reasons
2144 // discussed at web-page...
2145 default:
2146 fprintf (stderr,":-( mounted media[%X] is not supported\n",profile),
2147 exit(FATAL_START(EMEDIUMTYPE));
2148 break;
2149 }
2150
2151 if (velocity)
2152 fprintf (stderr,"%s: \"Current Write Speed\" is %.1fx%dKBps.\n",
2153 ioctl_device,velocity/(double)_1x,_1x);
2154
2155 if (next_wr_addr==(unsigned int)-1) do
2156 { unsigned char track[32];
2157
2158 next_wr_addr = 0;
2159
2160 cmd[0] = 0x52; // READ TRACK INFORMATION
2161 cmd[1] = 1;
2162 cmd[4] = next_track>>8;
2163 cmd[5] = next_track&0xFF; // last track, set up earlier
2164 cmd[8] = sizeof(track);
2165 cmd[9] = 0;
2166 if (cmd.transport (READ,track,sizeof(track)))
2167 break;
2168
2169 if (track[7]&1) // NWA_V
2170 { next_wr_addr = track[12]<<24;
2171 next_wr_addr |= track[13]<<16;
2172 next_wr_addr |= track[14]<<8;
2173 next_wr_addr |= track[15];
2174 }
2175
2176 if (next_wr_addr != // track start
2177 (unsigned int)(track[8]<<24|track[9]<<16|track[10]<<8|track[11]))
2178 fprintf (stderr,":-? resuming track#%d from LBA#%d\n",
2179 next_track,next_wr_addr);
2180
2181 } while (0);
2182 else next_wr_addr = 0;
2183
2184 return poor_mans_pwrite64;
2185 }
2186
2187 extern "C"
poor_man_rewritable(void * fd,void * buf)2188 int poor_man_rewritable (void *fd, void *buf)
2189 { Scsi_Command cmd(fd);
2190 int err,profile=mmc_profile&0xFFFF;
2191
2192 if (profile!=0x13 && // not DVD-RW Restricted Overwrite
2193 profile!=0x12 && // nor DVD-RAM
2194 profile!=0x1A && // nor DVD+RW
2195 profile!=0x2A && // nor DVD+RW Double Layer
2196 !(profile==0x41 && bdr_plus_pow) && // nor BD-R SRM+POW
2197 profile!=0x42 && // nor BD-R RRM
2198 profile!=0x43) // nor BD-RE
2199 return 0;
2200
2201 if (profile==0x13) // DVD-RW Restricted Overwrite
2202 { // Yet another restriction of Restricted Overwrite mode?
2203 // Pioneer DVR-x05 can't read a bit otherwise...
2204 do_reload=0;
2205 minus_rw_finalize (); // with do_reload==0!
2206 do_reload=1;
2207 }
2208 else if (profile==0x1A || // DVD+RW
2209 profile==0x2A || // DVD+RW Double Layer
2210 (profile&=0xF0)==0x40) // BD-R[E]
2211 { fprintf (stderr,"%s: flushing cache\n",ioctl_device);
2212 if (flush_cache(cmd)) exit (errno);
2213 }
2214
2215 cmd[0] = 0x28; // READ(10)
2216 cmd[5] = 16; // LBA#16, volume descriptor set
2217 cmd[8] = 16; // 32KB
2218 cmd[9] = 0;
2219 if ((err=cmd.transport (READ,buf,16*2048)))
2220 sperror ("READ@LBA=10h",err),
2221 exit(errno);
2222
2223 return 1;
2224 }
2225