1 /* $NetBSD$ */
2
3 /*
4 * File "udf_discinfo.c" is part of the UDFclient toolkit.
5 * File $Id: udf_discop.c,v 1.81 2017/01/16 14:33:06 reinoud Exp $ $Name: $
6 *
7 * Copyright (c) 2003, 2004, 2005, 2006, 2011
8 * Reinoud Zandijk <reinoud@netbsd.org>
9 * All rights reserved.
10 *
11 * The UDFclient toolkit is distributed under the Clarified Artistic Licence.
12 * A copy of the licence is included in the distribution as
13 * `LICENCE.clearified.artistic' and a copy of the licence can also be
14 * requested at the GNU foundantion's website.
15 *
16 * Visit the UDFclient toolkit homepage http://www.13thmonkey.org/udftoolkit/
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 */
30
31
32 /* XXX strip this XXX */
33 #include <stdio.h>
34 #include <fcntl.h>
35 #include <stdlib.h>
36 #include <errno.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <sys/ioctl.h>
40 #include <unistd.h>
41 #include <assert.h>
42 #include <dirent.h>
43 #include <string.h>
44 #include <strings.h>
45 #include <limits.h>
46
47 #include "uscsilib.h"
48
49
50 /* for locals */
51 #include "uscsilib.h"
52 #include "udf_discop.h"
53
54
55 #ifndef MAX
56 # define MAX(a,b) ((a)>(b)?(a):(b))
57 # define MIN(a,b) ((a)<(b)?(a):(b))
58 #endif
59
60
61 /* #define DEBUG(a) { a; } */
62 #define DEBUG(a) if (0) { a; }
63
64
65 /* globals */
66
67
68 /******************************************************************************************
69 *
70 * Tables and helper functions section
71 *
72 ******************************************************************************************/
73
read_cd_hex2(int val)74 int read_cd_hex2(int val) {
75 int nl, nh;
76
77 nl = val & 15;
78 nh = val >> 4;
79 if (nl >= 'A') nl -= 'A' + 10;
80 if (nh >= 'A') nh -= 'A' + 10;
81
82 return (nh*16) + nl;
83 }
84
85
read_cd_bcd(int val)86 int read_cd_bcd(int val) {
87 int nl, nh;
88
89 nl = (val & 15) - '0';
90 nh = (val >> 4) - '0';
91 if ((nl < 0 || nl > 9) || (nh < 0 || nh > 9)) return val;
92
93 return nh*10 + nl;
94 }
95
96
cd_msf2lba(int h,int m,int s,int f)97 int32_t cd_msf2lba(int h, int m, int s, int f) {
98 return 270000*h + 4500*m + 75*s + f - 150;
99 }
100
101
102 /******************************************************************************************
103 *
104 * Disc level operations
105 *
106 ******************************************************************************************/
107
udf_discinfo_is_cd_or_dvd(struct udf_discinfo * disc)108 int udf_discinfo_is_cd_or_dvd(struct udf_discinfo *disc) {
109 /* check device type */
110 switch (disc->devdrv_class & UDF_DEVDRV_CLASS) {
111 case UDF_DEVDRV_CLASS_FILE :
112 case UDF_DEVDRV_CLASS_DISC :
113 /* not nessisary */
114 return 0;
115 case UDF_DEVDRV_CLASS_CD :
116 case UDF_DEVDRV_CLASS_DVD :
117 /* it really is */
118 return 1;
119 default :
120 break;
121 }
122 return ENODEV;
123 }
124
125
udf_discinfo_check_disc_ready(struct udf_discinfo * disc)126 int udf_discinfo_check_disc_ready(struct udf_discinfo *disc) {
127 scsicmd cmd;
128 uint8_t buf[36];
129 int error;
130
131 if (!udf_discinfo_is_cd_or_dvd(disc)) return 1;
132
133 bzero(cmd, SCSI_CMD_LEN);
134 cmd[0] = 0; /* test unit ready */
135 error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 6, buf, 0, 30000, NULL);
136
137 return (error == 0);
138 }
139
140
141 #define blk_len 10000
udf_discinfo_set_recording_parameters(struct udf_discinfo * discinfo,int testwriting)142 int udf_discinfo_set_recording_parameters(struct udf_discinfo *discinfo, int testwriting) {
143 scsicmd cmd;
144 uint8_t res[blk_len];
145 uint8_t *pos;
146 uint32_t blockingnr;
147 int val_len, packet;
148 int error;
149
150 if (!udf_discinfo_is_cd_or_dvd(discinfo)) return 0;
151
152 /* Set up CD/DVD recording parameters */
153 if (!discinfo->recordable) return 0;
154
155 blockingnr = discinfo->blockingnr;
156
157 DEBUG(printf("Setting device's recording parameters\n"));
158 packet = discinfo->packet;
159
160 val_len = 0x32+2+8;
161 bzero(res, val_len);
162
163 pos = res + 8;
164
165 bzero(cmd, SCSI_CMD_LEN);
166 if (!packet) {
167 pos[ 0] = 0x05; /* page code 5 : cd writing */
168 pos[ 1] = 0x32; /* length in bytes */
169 pos[ 2] = 64 + 0; /* BUFE + write type 1 : track at once */
170 if (testwriting) pos[ 2] += 16;
171 pos[ 3] = (3<<6) | 5; /* next session OK, data packet, rec. incr. var packets */
172 pos[ 4] = 8; /* ISO mode 1 */
173 pos[ 8] = 0; /* normal CD-DA/CD-ROM or data disc */
174 DEBUG(printf("\tsetting up for sequential writing\n"));
175 } else {
176 pos[ 0] = 0x05; /* page code 5 : cd writing */
177 pos[ 1] = 0x32; /* length in bytes */
178 pos[ 2] = 0; /* write type 0 : packet/incremental */
179 if (testwriting) pos[ 2] += 16;
180 pos[ 3] = (3<<6) | 32 | 5; /* next session OK, data packet, rec. incr. fixed packets */
181 pos[ 4] = 10; /* ISO mode 2; XA form 1 */
182 pos[ 8] = 0x20; /* CD-ROM XA disc or DDCD disc */
183 pos[10] = (blockingnr >> 24) & 0xff; /* MSB packet size */
184 pos[11] = (blockingnr >> 16) & 0xff;
185 pos[12] = (blockingnr >> 8) & 0xff;
186 pos[13] = (blockingnr ) & 0xff; /* LSB packet size in SECTORS */
187 DEBUG(printf("\tsetting up for packet writing with packet size %d\n", blockingnr));
188 }
189
190 bzero(cmd, SCSI_CMD_LEN);
191 cmd[0] = 0x55; /* MODE SELECT (10) */
192 cmd[1] = 16; /* PF format */
193 cmd[7] = val_len >> 8; /* length of blob */
194 cmd[8] = val_len & 0xff;
195 cmd[9] = 0; /* control */
196
197 error = uscsi_command(SCSI_WRITECMD, discinfo->dev, cmd, 10, res, val_len, 3000, NULL);
198 if (error) {
199 perror("While WRTITING parameter page 5");
200 return error;
201 }
202
203 #if 0
204 /* Set CD/DVD speed to 'optimal' for it doesnt seem to do it automatically */
205 bzero(cmd, SCSI_CMD_LEN);
206 cmd[ 0] = 0xBB; /* Set CD speed */
207 cmd[ 1] = 1; /* select CAV (1) or CLV (0) recording */
208 cmd[ 2] = 0xff;
209 cmd[ 3] = 0xff; /* max read performance speed */
210 cmd[ 4] = 0xff;
211 cmd[ 5] = 0xff; /* max write performance speed; applic? */
212 cmd[11] = 0; /* control */
213 error = scsi_call(SCSI_WRITECMD, discinfo, cmd, 12, NULL, 0, NULL);
214 if (error) {
215 /* CAV not possible? then go for CLV */
216 cmd[ 1] = 0; /* select CAV (1) or CLV (0) recording */
217 error = scsi_call(SCSI_WRITECMD, discinfo, cmd, 12, NULL, 0, NULL);
218 if (error) {
219 perror("While setting speed");
220 return error;
221 }
222 }
223 #endif
224
225 /* flag OK */
226 return 0;
227 }
228 #undef blk_len
229
230
udf_discinfo_synchronise_caches(struct udf_discinfo * discinfo)231 int udf_discinfo_synchronise_caches(struct udf_discinfo *discinfo) {
232 scsicmd cmd;
233 int error;
234
235 /* bail out when we're in sequential emulation */
236 if (!udf_discinfo_is_cd_or_dvd(discinfo))
237 return 0;
238
239 bzero(cmd, SCSI_CMD_LEN);
240 cmd[ 0] = 0x35; /* Synchronise cache */
241 cmd[ 9] = 0; /* control */
242 error = uscsi_command(SCSI_WRITECMD, discinfo->dev, cmd, 10, NULL, 0, 30000, NULL);
243 if (error) {
244 perror("While synchronising write cache");
245 }
246
247 return error;
248 }
249
250
251 /*
252 * important: it must be called after write operations before read operations
253 * are allowed again. When its allready finished with writing this call has no
254 * effect and can be called at start to make sure the device knows that we're
255 * going to read.
256 */
udf_discinfo_finish_writing(struct udf_discinfo * discinfo)257 int udf_discinfo_finish_writing(struct udf_discinfo *discinfo) {
258 int error;
259
260 if (!udf_discinfo_is_cd_or_dvd(discinfo))
261 return 0;
262
263 error = udf_discinfo_synchronise_caches(discinfo);
264 return error;
265 }
266
267
udf_discinfo_reserve_track_in_logic_units(struct udf_discinfo * discinfo,uint32_t logic_units)268 int udf_discinfo_reserve_track_in_logic_units(struct udf_discinfo *discinfo, uint32_t logic_units) {
269 scsicmd cmd;
270 int error;
271
272 if (!udf_discinfo_is_cd_or_dvd(discinfo)) return ENODEV;
273
274 bzero(cmd, SCSI_CMD_LEN);
275 cmd[ 0] = 0x53; /* reserve track */
276 cmd[ 5] = (logic_units >> 24) & 0xff; /* size MSB */
277 cmd[ 6] = (logic_units >> 16) & 0xff;
278 cmd[ 7] = (logic_units >> 8) & 0xff;
279 cmd[ 8] = (logic_units ) & 0xff; /* size LSB */
280 cmd[ 9] = 0; /* control */
281 error = uscsi_command(SCSI_WRITECMD, discinfo->dev, cmd, 10, NULL, 0, 30000, NULL);
282
283 return error;
284 }
285
286
udf_discinfo_close_track(struct udf_discinfo * discinfo,uint16_t trackno)287 int udf_discinfo_close_track(struct udf_discinfo *discinfo, uint16_t trackno) {
288 scsicmd cmd;
289 int error;
290
291 if (!udf_discinfo_is_cd_or_dvd(discinfo)) return ENODEV;
292
293 bzero(cmd, SCSI_CMD_LEN);
294 cmd[ 0] = 0x5B; /* close session/track */
295 cmd[ 2] = 1; /* track */
296 cmd[ 4] = (trackno >> 8) & 0xff; /* specify trackno MSB */
297 cmd[ 5] = (trackno ) & 0xff; /* trackno LSB */
298 cmd[ 9] = 0; /* control */
299 error = uscsi_command(SCSI_WRITECMD, discinfo->dev, cmd, 10, NULL, 0, 30000, NULL);
300
301 return error;
302 }
303
304
305 /* can only close last session */
udf_discinfo_close_session(struct udf_discinfo * discinfo)306 int udf_discinfo_close_session(struct udf_discinfo *discinfo) {
307 scsicmd cmd;
308 int error;
309
310 if (!udf_discinfo_is_cd_or_dvd(discinfo)) return ENODEV;
311
312 bzero(cmd, SCSI_CMD_LEN);
313 cmd[ 0] = 0x5B; /* close session/track */
314 cmd[ 2] = 2; /* session */
315 cmd[ 9] = 0; /* control */
316 error = uscsi_command(SCSI_WRITECMD, discinfo->dev, cmd, 10, NULL, 0, 30000, NULL);
317
318 return error;
319 }
320
321
322 /*
323 * Repair a damaged track when suspected. It'll try to make it writable again.
324 * A track can be broken when sudden stops are made and the track end is left
325 * in a inconsistent state in the ATIP/PMA/TOC.
326 */
udf_discinfo_repair_track(struct udf_discinfo * discinfo,uint16_t trackno)327 int udf_discinfo_repair_track(struct udf_discinfo *discinfo, uint16_t trackno) {
328 scsicmd cmd;
329 int error;
330
331 if (!udf_discinfo_is_cd_or_dvd(discinfo)) return ENODEV;
332
333 bzero(cmd, SCSI_CMD_LEN);
334 cmd[ 0] = 0x58; /* repair track */
335 cmd[ 4] = (trackno >> 8) & 0xff; /* specify trackno MSB */
336 cmd[ 5] = (trackno ) & 0xff; /* trackno LSB */
337 cmd[ 9] = 0; /* control */
338 error = uscsi_command(SCSI_WRITECMD, discinfo->dev, cmd, 10, NULL, 0, 30000, NULL);
339
340 return error;
341 }
342
343
344 /*
345 * This routine 'get disc type' tries to get operational information from the
346 * disc/drive combination and its capabilities. Fills in devdrv_class, MMC
347 * profile and the various flags; no track info.
348 */
349
udf_discinfo_get_disc_type(struct udf_discinfo * disc)350 int udf_discinfo_get_disc_type(struct udf_discinfo *disc) {
351 struct stat stat;
352 scsicmd cmd;
353 uint8_t buf[256];
354 uint8_t features[1024+100], *rpos, *fpos;
355 uint32_t pos, features_len, feat_tbl_len, val_len;
356 uint32_t feature, last_feature;
357 uint32_t feature_ver, feature_pers, feature_cur, feature_len;
358 int error;
359
360 /* assume generic CD-ROM with no known MMC profile */
361 disc->devdrv_class = UDF_DEVDRV_CLASS_CD;
362 disc->mmc_profile = 0;
363
364 /* check if its a regular file */
365 fstat(disc->dev->fhandle, &stat);
366 if (S_ISREG(stat.st_mode)) {
367 UDF_VERBOSE(printf("UDF device %s is a regular file\n", disc->dev->dev_name));
368 disc->devdrv_class = UDF_DEVDRV_CLASS_FILE;
369 disc->sequential = 0; /* full r/w */
370 disc->recordable = 1; /* assuming rw access */
371 disc->blankable = 0; /* not applicable */
372 disc->rewritable = 1;
373 disc->packet = 0;
374 disc->blockingnr = 1;
375 disc->strict_overwrite = 0;
376 disc->sector_size = DISC_SECTOR_SIZE;
377 return 0;
378 }
379
380 /* check if its a ATIPI/SCSI device */
381 error = uscsi_check_for_scsi(disc->dev);
382 if (error) {
383 /* obviously no ATIPI/SCSI device -> has to be IDE disc or other but no file either */
384 disc->devdrv_class = UDF_DEVDRV_CLASS_DISC;
385 disc->sequential = 0; /* full r/w */
386 disc->recordable = 1; /* assuming rw access */
387 disc->blankable = 0; /* not applicable */
388 disc->rewritable = 1;
389 disc->packet = 0;
390 disc->blockingnr = 1;
391 disc->strict_overwrite = 0;
392 disc->sector_size = DISC_SECTOR_SIZE;
393 UDF_VERBOSE(printf("Got error executing SCSI command, assuming IDE disc\n"));
394 return 0;
395 }
396
397 /* check if its a SCSI disc -> if so, do NOT issue mmc profile check */
398 bzero(cmd, SCSI_CMD_LEN);
399 cmd[0] = 0x12; /* INQUIRY */
400 cmd[1] = 0; /* basic inquiry */
401 cmd[2] = 0; /* no page or operation code */
402 cmd[3] = 0; /* reserved/MSB result */
403 cmd[4] = 96; /* all but vendor specific */
404 cmd[5] = 0; /* control */
405 error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 6, buf, 96, 30000, NULL);
406 if (error) {
407 fprintf(stderr, "Device claims to be SCSI but does NOT respond to inquiry!\n");
408 return ENOENT;
409 }
410 disc->scsi_device_type = buf[0] & 0x1f;
411
412 switch (disc->scsi_device_type) {
413 case 0x05 : break; /* MMC */
414 case 0x00 : /* Direct access device */
415 case 0x0E : /* Simplified direct access device */
416 /* read-write possible */
417 disc->devdrv_class = UDF_DEVDRV_CLASS_DISC;
418 disc->sequential = 0; /* full r/w */
419 disc->recordable = 1; /* assuming rw access */
420 disc->blankable = 0; /* not applicable */
421 disc->rewritable = 1;
422 disc->packet = 0;
423 disc->blockingnr = 1;
424 disc->strict_overwrite = 0;
425 disc->sector_size = DISC_SECTOR_SIZE;
426 return 0;
427 case 0x04 :
428 case 0x07 :
429 /* Non MMC read only optical media */
430 disc->devdrv_class = UDF_DEVDRV_CLASS_DISC;
431 disc->sequential = 0; /* */
432 disc->recordable = 0; /* assuming ro access */
433 disc->blankable = 0; /* not applicable */
434 disc->rewritable = 0;
435 disc->packet = 0;
436 disc->blockingnr = 1;
437 disc->strict_overwrite = 0;
438 disc->sector_size = DISC_SECTOR_SIZE;
439 return 0;
440 default:
441 fprintf(stderr, "Device type 0x%02x not suitable for mass storage\n", disc->scsi_device_type);
442 return ENOENT;
443 }
444
445 /* get MMC profile */
446 bzero(cmd, SCSI_CMD_LEN);
447 cmd[ 0] = 0x46; /* Get configuration */
448 cmd[ 8] = 32; /* just a small buffer size */
449 cmd[ 9] = 0; /* control */
450 error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 10, buf, 32, 30000, NULL);
451 if (!error) {
452 disc->mmc_profile = buf[7] | (buf[6] << 8);
453 } else {
454 disc->mmc_profile = 0; /* mark unknown MMC profile */
455 }
456 UDF_VERBOSE_MAX(printf("Device has MMC profile 0x%02x\n", disc->mmc_profile));
457
458 /* determine CD sector size */
459 bzero(buf, 8);
460 bzero(cmd, SCSI_CMD_LEN);
461 cmd[0] = 0x25; /* CD READ RECORDED CAPACITY */
462 error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 10, buf, 8, 30000, NULL);
463 if (error) {
464 fprintf(stderr, "Can't read CD recorded capacity; assuming sector size %d : %s", CD_SECTOR_SIZE, strerror(error));
465 disc->sector_size = CD_SECTOR_SIZE;
466 } else {
467 disc->sector_size = buf[7] | (buf[6]<<8) | (buf[5]<<16) | (buf[4]<<24);
468 /* packet size is recorded for each track seperately */
469 }
470
471 /*
472 * Read in features to determine device flags. First take some initial
473 * values.
474 */
475 disc->sequential = 0;
476 disc->recordable = 0;
477 disc->erasable = 0;
478 disc->blankable = 0;
479 disc->formattable = 0;
480 disc->rewritable = 0;
481 disc->mrw = 0;
482 disc->packet = 0;
483 disc->strict_overwrite = 0;
484 disc->blockingnr = 1; /* not relevant if non packet write */
485
486 feat_tbl_len = 1024;
487 last_feature = feature = 0;
488 do {
489 bzero(cmd, SCSI_CMD_LEN);
490 cmd[0] = 0x46; /* Get configuration */
491 cmd[1] = 0; /* RT=0 -> all independent of current setting */
492 cmd[2] = (last_feature) >> 8; /* MSB feature number */
493 cmd[3] = (last_feature) & 0xff; /* LSB feature number */
494 cmd[7] = (feat_tbl_len) >> 8; /* MSB buffersize */
495 cmd[8] = (feat_tbl_len) & 0xff; /* LSB buffersize */
496 cmd[9] = 0; /* control */
497 error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 10, features, feat_tbl_len, 30000, NULL);
498 if (error) {
499 fprintf(stderr, "While reading feature table : %s\n", strerror(error));
500 return EIO;
501 }
502
503 features_len = features[3] | (features[2]<<8) | (features[1]<<16) | (features[0]<<24);
504 disc->mmc_profile = features[7] | (features[6]<<8);
505
506 pos = 8;
507 while (pos < features_len) {
508 fpos = &features[pos];
509
510 feature = fpos[1] | (fpos[0] << 8);
511 feature_ver = (fpos[2] >> 2) & 15;
512 feature_cur = (fpos[2] & 1);
513 feature_pers= (fpos[2] & 2);
514 feature_len = fpos[3];
515
516 if (feature_cur == 1) {
517 rpos = &fpos[4];
518 switch (feature) {
519 case 0x0010 : /* random readable feature */
520 disc->sector_size = rpos[3] | (rpos[2] << 8) | (rpos[1] << 16) | (rpos[0] << 24);
521 disc->blockingnr = rpos[5] | (rpos[4] << 8);
522 /* RW error page */
523 break;
524 case 0x0020 : /* random writable feature */
525 disc->recordable = 1;
526 disc->rewritable = 1;
527 break;
528 case 0x0021 : /* incremental streaming write feature */
529 disc->recordable = 1;
530 disc->sequential = 1;
531 disc->link_size = rpos[7];
532 if (rpos[6] & 1)
533 disc->link_size = 0;
534 break;
535 case 0x0022 : /* (obsolete) erase support feature */
536 disc->recordable = 1;
537 disc->erasable = 1;
538 break;
539 case 0x0023 : /* formatting media support feature */
540 disc->recordable = 1;
541 disc->formattable = 1;
542 break;
543 case 0x0024 : /* hardware assisted defect management feature */
544 /* XXX set mrw ? */
545 break;
546 case 0x0025 : /* write once */
547 disc->recordable = 1;
548 break;
549 case 0x0026 : /* restricted overwrite feature */
550 disc->recordable = 1;
551 disc->rewritable = 1;
552 disc->strict_overwrite = 1;
553 break;
554 case 0x0028 : /* MRW formatted media support feature */
555 disc->mrw = 1;
556 break;
557 case 0x002b : /* read/write DVD+R formatted media */
558 disc->sequential = 1;
559 if (rpos[0] & 1) /* write support */
560 disc->recordable = 1;
561 break;
562 case 0x002c : /* regid restricted overwrite feature */
563 disc->recordable = 1;
564 disc->rewritable = 1;
565 disc->strict_overwrite = 1;
566 if (rpos[0] & 1) /* blank bit */
567 disc->blankable = 1;
568 break;
569 case 0x002d : /* track at once recording feature */
570 disc->recordable = 1;
571 disc->sequential = 1;
572 break;
573 case 0x002f : /* DVD-R/-RW write feature */
574 disc->recordable = 1;
575 if (rpos[0] & 2) /* DVD-RW bit */
576 disc->blankable = 1;
577 break;
578 case 0x0038 : /* pseuro overwritable */
579 break;
580 default :
581 /* ignore */
582 break;
583 }
584 }
585
586 last_feature = MAX(last_feature, feature);
587 if (feature_len & 3) {
588 UDF_VERBOSE(printf("Drive returned feature %d %swith bad length %d\n",
589 feature, (feature_cur == 1? "(current) ":""), feature_len));
590 feature_len = (feature_len + 3) & ~3;
591 }
592 pos += 4 + feature_len;
593 }
594 } while (features_len >= 0xffff);
595
596 /*
597 * fixup DVD and CD-RW drives that are on crack.
598 */
599 if (disc->mmc_profile == 0x0a) {
600 /* some forget to mention strict overwrite when not sequential and forget the blocking size */
601 if (!disc->sequential) {
602 disc->strict_overwrite = 1;
603 disc->blockingnr = 32; /* fixed for CD-RW */
604 }
605 /* some say they are strict overwrite but also sequential */
606 if (disc->strict_overwrite)
607 disc->sequential = 0;
608 /* some forget that if they are mrw they can't the be other */
609 if (disc->mrw) {
610 disc->sequential = 0;
611 disc->strict_overwrite = 0;
612 }
613 }
614 /* some think a CD-R is rewritable */
615 if (disc->mmc_profile == 0x09) {
616 disc->rewritable = 0;
617 }
618
619 /* derivatives */
620 if (disc->blockingnr > 1)
621 disc->packet = 1;
622
623 switch (disc->mmc_profile) {
624 case 0x01 :
625 case 0x02 :
626 /* SCSI discs class; treat like normal discs */
627 disc->devdrv_class = UDF_DEVDRV_CLASS_DISC;
628 UDF_VERBOSE(printf("SCSI disc detected; treating like normal disc device\n"));
629 return 0;
630 case 0x03 : /* Magneto Optical with sector erase */
631 case 0x04 : /* Magneto Optical write once */
632 case 0x05 : /* Advance Storage Magneto Optical */
633 disc->devdrv_class = UDF_DEVDRV_CLASS_MO;
634 break;
635 /* 0x00, 0x08, 0x09, 0x0a : different types of CD-ROM devices like CD-R/RW etc. */
636 case 0x00 :
637 disc->devdrv_class = UDF_DEVDRV_CLASS_CD; /* not allways clear */
638 break;
639 case 0x08 : /* CD-ROM */
640 case 0x09 : /* CD-R */
641 case 0x0a : /* CD-RW */
642 disc->devdrv_class = UDF_DEVDRV_CLASS_CD;
643 break;
644 /* 0x10...0x14 DVD-ROM and DVD- devices */
645 case 0x10 : /* DVD-ROM */
646 case 0x11 : /* DVD-R */
647 case 0x12 : /* DVD-RAM */
648 case 0x13 : /* DVD-RW (restricted overwrite) */
649 case 0x14 : /* DVD-RW (sequential) */
650 /* 0x1a..0x1b DVD+ devices */
651 case 0x1a : /* DVD+RW */
652 case 0x1b : /* DVD+R */
653 case 0x2b : /* DVD+R double layer */
654 disc->devdrv_class = UDF_DEVDRV_CLASS_DVD;
655 break;
656 case 0x40 : /* BD-ROM */
657 case 0x41 : /* BD-R Sequential Recording (SRM) */
658 case 0x42 : /* BD-R Random Recording (RRM) */
659 case 0x43 : /* BD-RE */
660 disc->devdrv_class = UDF_DEVDRV_CLASS_BD;
661 break;
662 default :
663 fprintf(stderr, "Not recognized MMC profile %d encountered, marking readonly\n", disc->mmc_profile);
664 disc->devdrv_class = UDF_DEVDRV_CLASS_CD; /* go for the `dummy' */
665 break;
666 }
667
668 /*
669 * ok, if we're on an CD-MRW or DVD+MRW, we ought to have switched
670 * automatically to DMA space. However, this drive at times just
671 * refuses with all messy things around.
672 */
673
674
675 /* Select `Defect managed area' LBA space */
676 if (!disc->mrw)
677 return 0;
678
679 DEBUG(printf("Setting DMA LBA space"));
680
681 val_len = 6 + 8 + 2; /* 2 for 4 byte alignment */
682 rpos = buf + 8;
683 bzero(buf, val_len);
684
685 rpos[ 0] = 0x03; /* GAA/DMA space select */
686 rpos[ 1] = 6; /* page length */
687 rpos[ 3] = 0; /* select GAA bit in bit 0 */
688
689 bzero(cmd, SCSI_CMD_LEN);
690 cmd[0] = 0x55; /* MODE SELECT (10) */
691 cmd[1] = 16; /* PF format */
692 cmd[7] = val_len >> 8; /* length of blob */
693 cmd[8] = val_len & 0xff;
694 cmd[9] = 0; /* control */
695
696 error = uscsi_command(SCSI_WRITECMD, disc->dev, cmd, 10, buf, val_len, 30000, NULL);
697 if (error) {
698 perror("While WRTITING parameter page 3");
699 return error;
700 }
701
702 /* shutup gcc */
703 feature_pers = feature_pers; feature_ver = feature_ver;
704
705 return 0;
706 }
707
708 #if defined(__NetBSD__) || defined(__OpenBSD__)
709 #include <sys/ioctl.h>
710 #include <sys/disklabel.h>
711 #include <sys/dkio.h>
712
udf_get_partition_info(struct udf_discinfo * disc)713 int udf_get_partition_info(struct udf_discinfo *disc) {
714 struct disklabel disklab;
715 struct partition *dp;
716 struct stat st;
717 int partnr;
718
719 /* read disklabel partition */
720 if (ioctl(disc->dev->fhandle, DIOCGDINFO, &disklab) == -1) {
721 /* failed to get disclabel! */
722 perror("disklabel");
723 return errno;
724 }
725
726 /* get disk partition it refers to */
727 fstat(disc->dev->fhandle, &st);
728 partnr = DISKPART(st.st_rdev);
729 dp = &disklab.d_partitions[partnr];
730
731 if (dp->p_size == 0) {
732 perror("faulty disklabel partition returned, check label\n");
733 return EIO;
734 }
735
736 disc->sector_size = disklab.d_secsize;
737 disc->session_start [0] = 0;
738 disc->session_end [0] = dp->p_size - 1;
739
740 return 0;
741 }
742
743 #elif defined(__linux__)
744 #include <linux/fs.h>
745
udf_get_partition_info(struct udf_discinfo * disc)746 int udf_get_partition_info(struct udf_discinfo *disc) {
747 long p_size, p_size512;
748 int secsize;
749
750 /* get device length and sector size */
751 if (ioctl(disc->dev->fhandle, BLKSSZGET, &secsize) == -1) {
752 perror("Can't read my sector size\n");
753 return errno;
754 }
755 if (ioctl(disc->dev->fhandle, BLKGETSIZE, &p_size512) == -1) {
756 perror("Can't read my partition size\n");
757 return errno;
758 }
759
760 p_size = p_size512 * (secsize / 512);
761
762 disc->sector_size = secsize;
763 disc->session_start [0] = 0;
764 disc->session_end [0] = p_size - 1;
765
766 return 0;
767 }
768
769 #else
770
udf_get_partition_info(struct udf_discinfo * disc)771 int udf_get_partition_info(struct udf_discinfo *disc) {
772 perror(" UDF: no explicit support for disc devices yet for this operating system.\n");
773 perror("Trying readonly access...\n");
774
775 disc->recordable = disc->rewritable = 0;
776
777 return 0;
778 }
779
780 #endif
781
782
783 /* 10000 is arbitrary */
784 /* TODO split up one day for its updating values unnessisarily */
785 #define res_len 10000
udf_get_disc_info(struct udf_discinfo * disc)786 int udf_get_disc_info(struct udf_discinfo *disc) {
787 scsicmd cmd;
788 struct stat stat;
789 uint32_t val_len;
790 uint32_t first_track, last_track;
791 uint32_t first_session, last_session;
792 uint32_t next_writable_addr, packet_size;
793 uint32_t cntrl, addr, tno, point, min, sec, frame, pmin, psec, pframe;
794 uint32_t data_length, pos;
795 uint8_t res[res_len];
796 int first_track_last_session, last_track_last_session;
797 int track, session, sector_size;
798 int nwa_valid;
799 off_t track_start, track_end, track_size, disc_size, free_blocks;
800 int error;
801
802 if (disc->devdrv_class == UDF_DEVDRV_CLASS_FILE) {
803 sector_size = disc->alt_sector_size ? disc->alt_sector_size : disc->sector_size;
804 fstat(disc->dev->fhandle, &stat);
805 disc->link_size = 0; /* no link lossage */
806 disc->disc_state = DISC_STATE_NOT_SERIAL;
807 disc->last_session_state = SESSION_STATE_INCOMPLETE;
808 disc->num_sessions = 1;
809 disc->session_start [0] = 0;
810 disc->session_end [0] = (stat.st_size / sector_size); /* inclusive */
811 disc->next_writable [0] = (stat.st_size / sector_size) + 1;
812 disc->packet_size [0] = stat.st_blksize / sector_size;
813 return 0;
814 }
815
816 if (disc->devdrv_class == UDF_DEVDRV_CLASS_DISC) {
817 disc->link_size = 0; /* no link lossage */
818 disc->disc_state = DISC_STATE_NOT_SERIAL;
819 disc->last_session_state = SESSION_STATE_COMPLETE;
820 disc->num_sessions = 1;
821
822 disc->session_start [0] = 0;
823 disc->session_end [0] = 0;
824
825 error = udf_get_partition_info(disc);
826 if (error)
827 return error;
828
829 fprintf(stderr, "UDF: warning... reading/writing on 'disc' device\n");
830 return 0;
831 }
832
833 /* classes CD and DVD remain; we can be on a DVD/CD recordable or on a legacy CD-ROM */
834
835 /* Get track information */
836 val_len = 12;
837 bzero(res, val_len);
838 bzero(cmd, SCSI_CMD_LEN);
839
840 cmd[0] = 0x51; /* Read disc information */
841 cmd[7] = val_len >> 8; /* MSB allocation length */
842 cmd[8] = val_len & 0xff; /* LSB allocation length */
843 cmd[9] = 0; /* control */
844 error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 10, res, val_len, 30000, NULL);
845
846 if (!error) {
847 /* we are a MMC3+ device! */
848 disc->disc_state = res[2] & 3; /* just 'happends' to be the same as we use */
849 disc->last_session_state = (res[2] >> 2) & 3; /* ditto */
850 disc->blankable = res[2] & 16; /* blankable -> update possibility */
851 disc->num_sessions = res[4] | (res[ 9] << 8);
852 first_track = res[3];
853 first_track_last_session = res[5] | (res[10] << 8); /* to build up the last 'session' */
854 last_track_last_session = res[6] | (res[11] << 8);
855
856 /* Initialise the sessions to be taken as overspanning tracks */
857 for (session = 0; session < disc->num_sessions; session++) {
858 disc->session_start[session] = INT_MAX;
859 disc->session_end [session] = 0;
860 }
861
862 for (track = first_track; track <= last_track_last_session; track++) {
863 /* each track record is 36 bytes long */
864 val_len = 36;
865 bzero(res, val_len);
866
867 bzero(cmd, SCSI_CMD_LEN);
868 cmd[0] = 0x52; /* Read track information */
869 cmd[1] = 1; /* indexed on track */
870 cmd[4] = track >> 8; /* track number 0-0xff ? */
871 cmd[5] = track & 0xff;
872 cmd[7] = val_len >> 8; /* MSB length resultbuf */
873 cmd[8] = val_len & 0xff; /* LSB ,, */
874 cmd[9] = 0;
875 error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 10, res, val_len, 30000, NULL);
876 if (error) {
877 perror("While reading track info");
878 break;
879 }
880 #if 0
881 data_length = res[1] | (res[0] << 8);
882 // track_number = res[2] | (res[32] << 8); /* why? */
883 session = res[3] | (res[33] << 8);
884 // is_track_mode = res[5] & 15;
885 // is_copy = res[5] & 16;
886 // is_damage = res[5] & 32;
887 // is_fixed_packet = res[6] & 16;
888 // is_packet_or_inc = res[6] & 32;
889 // is_blank = res[6] & 64;
890 // is_reserved = res[6] & 128;
891 // is_data_mode = res[6] & 15;
892 nwa_valid = res[7] & 1;
893 // lra_valid = res[7] & 2;
894 #endif
895 data_length = res[1] | (res[0] << 8);
896 session = res[3] | (res[33] << 8);
897 nwa_valid = res[7] & 1;
898
899 track_start = res[11] | (res[10]<<8) | (res[ 9]<<16) | (res[ 8]<<24);
900 next_writable_addr = res[15] | (res[14]<<8) | (res[13]<<16) | (res[12]<<24);
901 free_blocks = res[19] | (res[18]<<8) | (res[17]<<16) | (res[16]<<24);
902 packet_size = res[23] | (res[22]<<8) | (res[21]<<16) | (res[20]<<24);
903 track_size = res[27] | (res[26]<<8) | (res[25]<<16) | (res[24]<<24);
904 /* last_recorded_addr = res[32] | (res[30]<<8) | (res[29]<<16) | (res[28]<<24); */
905 track_end = track_start + track_size;
906
907 if (data_length <= 30) session &= 0xff;
908
909 disc->session_start[session-1] = MIN(disc->session_start[session-1], track_start);
910 disc->session_end [session-1] = MAX(disc->session_end [session-1], track_end);
911 disc->free_blocks [session-1] = free_blocks;
912 disc->packet_size [session-1] = packet_size;
913 if (nwa_valid) disc->next_writable[session-1] = next_writable_addr;
914 }
915 if (disc->session_start[disc->num_sessions-1] == INT_MAX) {
916 if (disc->disc_state == DISC_STATE_FULL) {
917 if (disc->last_session_state == SESSION_STATE_COMPLETE) disc->num_sessions--;
918 }
919 }
920
921 /* XXX
922 * initialise default link size to zero; only set DEFAULT
923 * link lossage for CD-R we are using `Burn Free' for writing
924 * but if it fails its good to know the penalty for recovery
925 * XXX
926 */
927 disc->link_size = 0;
928 if (disc->mmc_profile == 0x09) {
929 disc->link_size = 7;
930 }
931
932 return 0;
933 }
934
935 /* Start with legacy CD-ROM .... trying to get as much info from it as possible */
936 disc->sequential = 0;
937 disc->recordable = 0;
938 disc->blankable = 0;
939 disc->packet = 0;
940 disc->blockingnr = 32;
941 disc->strict_overwrite = 0;
942 disc->disc_state = DISC_STATE_FULL;
943 disc->last_session_state = SESSION_STATE_COMPLETE;
944 disc->link_size = 7; /* DEFAULT link lossage for CDs */
945
946
947 /* Read session range */
948 val_len = 4; /* only head */
949 bzero(res, val_len);
950 bzero(cmd, SCSI_CMD_LEN);
951 cmd[0] = 0x43; /* READ TOC/PMA/ATIP INFO */
952 cmd[1] = 2; /* no LBA's are defined */
953 cmd[2] = 2; /* format 2 also this time */
954 cmd[6] = 0; /* obligatory zero */
955 cmd[7] = val_len >> 8;
956 cmd[8] = val_len & 0xff;
957 cmd[9] = 0;
958 error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 10, res, val_len, 30000, NULL);
959 if (error) {
960 perror("TOC reading of sessions failed");
961 return error;
962 }
963 first_session = read_cd_hex2(res[2]);
964 last_session = read_cd_hex2(res[3]);
965
966 disc->num_sessions = last_session - first_session + 1;
967
968 /* Initialise the sessions to be taken as overspanning tracks */
969 for(session = 0; session <= disc->num_sessions; session++) {
970 disc->session_start[session] = INT_MAX;
971 disc->session_end [session] = 0;
972 }
973
974 /* calculate how big the result buffer ought to be to get the whole TOC */
975 /* NOTE: don't count the 2 length bytes */
976 val_len = res[1] + (res[0] << 8);
977
978 /* fix length for ATAPI drives */
979 if (val_len & 1)
980 val_len++;
981
982 assert(val_len < res_len);
983
984 /* Read the complete TOC and extract information */
985 bzero(res, val_len);
986 bzero(cmd, SCSI_CMD_LEN);
987 cmd[0] = 0x43; /* READ TOC/PMA/ATIP INFO */
988 cmd[1] = 2; /* LBA's are not defined */
989 cmd[2] = 2; /* format 2; full TOC */
990 cmd[6] = first_session; /* start at first session */
991 cmd[7] = val_len >> 8;
992 cmd[8] = val_len & 0xff;
993 cmd[9] = 0;
994 error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 10, res, val_len, 30000, NULL);
995 if (error) {
996 perror("TOC reading of full TOC failed");
997 return error;
998 }
999
1000 data_length =res[1] | (res[0] << 8);
1001 if (data_length != val_len) {
1002 fprintf(stderr, "Warning: device didn't return all data requested when reading full TOC\nn");
1003 fprintf(stderr, "\treturned %d bytes instead of %d\n", data_length, val_len);
1004 }
1005 pos = 4;
1006 track_start = INT_MAX; track_end = 0;
1007
1008 while (pos < data_length + 2) {
1009 session = read_cd_bcd(res[pos+ 0]);
1010 cntrl = res[pos+1] & 15;
1011 addr = res[pos+1] >> 4;
1012 tno = read_cd_bcd(res[pos+ 2]);
1013 point = read_cd_bcd(res[pos+ 3]);
1014 min = read_cd_bcd(res[pos+ 4]);
1015 sec = read_cd_bcd(res[pos+ 5]);
1016 frame = read_cd_bcd(res[pos+ 6]);
1017 pmin = read_cd_bcd(res[pos+ 8]);
1018 psec = read_cd_bcd(res[pos+ 9]);
1019 pframe = read_cd_bcd(res[pos+10]);
1020
1021 /* extract information; explicit writeout. See SCSI docs */
1022 if (tno == 0 && session && addr == 1) {
1023 switch (point) {
1024 case 0xa0 : first_track = pmin; break;
1025 case 0xa1 : last_track = pmin; break;
1026 case 0xa2 :
1027 track_end = cd_msf2lba(0, pmin, psec, pframe);
1028 disc->session_end [session-1] = MAX(disc->session_end [session-1], track_end);
1029 break;
1030 default :
1031 track_start = cd_msf2lba(0, pmin, psec, pframe);
1032 disc->session_start[session-1] = MIN(disc->session_start[session-1], track_start);
1033 break;
1034 }
1035 }
1036 if (tno == 0 && session && addr == 5) {
1037 if (point == 0xb0) {
1038 next_writable_addr = cd_msf2lba(0, min, sec, frame);
1039 disc_size = cd_msf2lba(0, pmin, psec, pframe);
1040 /* TODO use nwa & size */
1041 printf("UDF: ignoring B0 Q channel : next writable address; pre MMC3 device; fix me\n");
1042 }
1043
1044 }
1045 pos += 11;
1046 }
1047
1048 /* Last session information is notoriously flawed in TOC format so update it */
1049 bzero(res, 8);
1050 bzero(cmd, SCSI_CMD_LEN);
1051 cmd[0] = 0x25; /* CD READ RECORDED CAPACITY */
1052 error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 10, res, 8, 30000, NULL);
1053 if (error) {
1054 fprintf(stderr, "Can't read CD recorded capacity, last session end might not be OK : %s\n", strerror(error));
1055 return 0;
1056 }
1057
1058 session = disc->num_sessions-1;
1059 disc->session_end[session] = res[3] | (res[2]<<8) | (res[1]<<16) | (res[0]<<24);
1060
1061 /* shut up gcc */
1062 disc_size = disc_size; first_track_last_session = first_track_last_session;
1063 cntrl = cntrl; last_track = last_track;
1064
1065 return 0;
1066 }
1067 #undef res_len
1068
1069
udf_open_disc(char * dev_name,int discop_flags,struct udf_discinfo ** discptr)1070 int udf_open_disc(char *dev_name, int discop_flags, struct udf_discinfo **discptr) {
1071 struct udf_discinfo *disc;
1072
1073 if (!discptr) return EINVAL;
1074 *discptr = NULL;
1075
1076 /* determine what kind of file/device we are dealing with */
1077 disc = calloc(1, sizeof(struct udf_discinfo));
1078 if (!disc) return ENOMEM;
1079
1080 disc->dev = calloc(1, sizeof(struct uscsi_dev));
1081 if (!disc->dev) {
1082 free(disc);
1083 return ENOMEM;
1084 }
1085
1086 /* fill in the name */
1087 disc->dev->dev_name = strdup(dev_name);
1088
1089 if (uscsi_open(disc->dev) != 0) {
1090 perror("Failure to open device or file");
1091 free(disc->dev);
1092 free(disc);
1093 return ENODEV;
1094 }
1095
1096 /* determine disc type */
1097 if (udf_discinfo_get_disc_type(disc)) {
1098 perror("Error during classification of disc; skipping disc\n");
1099 uscsi_close(disc->dev);
1100 free(disc->dev);
1101 free(disc);
1102 return ENODEV;
1103 }
1104
1105 /* get disc info */
1106 if (udf_get_disc_info(disc)) {
1107 fprintf(stderr, "Can't get disc info");
1108 uscsi_close(disc->dev);
1109 free(disc->dev);
1110 free(disc);
1111 return ENODEV;
1112 }
1113
1114 /* process discop_flags */
1115 if (discop_flags & UDF_DISCOP_BSWAP)
1116 disc->bswap_sectors = 1;
1117
1118 /* return the pointer */
1119 *discptr = disc;
1120
1121 /* set recording parameters */
1122 udf_discinfo_set_recording_parameters(disc, 0); /* no testwrite */
1123
1124 return 0;
1125 }
1126
1127
udf_close_disc(struct udf_discinfo * disc)1128 int udf_close_disc(struct udf_discinfo *disc) {
1129 if (!disc) return 0;
1130
1131 /* udf_stop_disc_thread(disc); */
1132 uscsi_close(disc->dev);
1133
1134 printf("Disc access statistics\n");
1135 printf("\tsector reads %8"PRIu64" (%"PRIu64" Kbyte)\n", disc->sectors_read, ((uint64_t) (disc->sectors_read) * disc->sector_size) / 1024);
1136 printf("\tsector written %8"PRIu64" (%"PRIu64" Kbyte)\n", disc->sectors_written, ((uint64_t) (disc->sectors_written) * disc->sector_size) / 1024);
1137 printf("\tswitches %8d\n", disc->switchings);
1138
1139 return 0;
1140 }
1141
1142
1143
udf_discinfo_alter_perception(struct udf_discinfo * disc,uint32_t sec_size,uint32_t num_sectors)1144 int udf_discinfo_alter_perception(struct udf_discinfo *disc, uint32_t sec_size, uint32_t num_sectors) {
1145 struct stat stat;
1146
1147 assert(disc);
1148 if ((disc->devdrv_class & UDF_DEVDRV_CLASS) != UDF_DEVDRV_CLASS_FILE) {
1149 return EINVAL;
1150 }
1151
1152 fstat(disc->dev->fhandle, &stat);
1153 if (sec_size == 0) sec_size = disc->sector_size;
1154 if (num_sectors == 0) num_sectors = stat.st_size / sec_size;
1155
1156 if (((sec_size % 512) != 0) || (sec_size == 0)) {
1157 fprintf(stderr, "Size of blocks need to be a multiple of 512\n");
1158 return EINVAL;
1159 }
1160
1161 if (stat.st_size / sec_size >= (uint32_t) -1)
1162 {
1163 fprintf(stderr, "Disc needs to many logical sectors, please increase blocksize\n");
1164 return EINVAL;
1165 }
1166
1167 if (num_sectors < 300) {
1168 fprintf(stderr, "Disc size too small to put an UDF filingsystem on\n");
1169 return EINVAL;
1170 }
1171
1172 if (stat.st_size != (off_t) sec_size * num_sectors) {
1173 fprintf(stderr, "Size of image file is not equal to specified size parameters\n");
1174 return EINVAL;
1175 }
1176
1177 disc->sequential = 0; /* full r/w */
1178 disc->recordable = 1; /* assuming rw access */
1179 disc->rewritable = 1;
1180 disc->sector_size = sec_size;
1181 disc->alt_sector_size = sec_size; /* altered value */
1182 disc->link_size = 0; /* no link lossage */
1183 disc->disc_state = DISC_STATE_NOT_SERIAL;
1184 disc->last_session_state = SESSION_STATE_INCOMPLETE;
1185 disc->num_sessions = 1;
1186 disc->session_start [0] = 0;
1187 disc->session_end [0] = num_sectors;
1188 disc->next_writable [0] = num_sectors + 1;
1189 disc->packet_size [0] = stat.st_blksize / sec_size; /* best blocking size */
1190
1191 return 0;
1192 }
1193
1194
1195 /******************************************************************************************
1196 *
1197 * Sector readers and writers
1198 *
1199 ******************************************************************************************/
1200
1201
1202 /* read an extent of sectors in the `result' buffer */
udf_read_physical_sectors(struct udf_discinfo * disc,off_t sector,uint32_t num_sectors,char * what,uint8_t * result)1203 int udf_read_physical_sectors(struct udf_discinfo *disc, off_t sector, uint32_t num_sectors, char *what, uint8_t *result) {
1204 struct uscsi_sense sense;
1205 scsicmd cmd;
1206 int size, size_read, chunk;
1207 uint32_t session, skipped, sector_size;
1208 int pos, lb, hb, error;
1209
1210 /* protect us */
1211 if (((long) result) & 3) {
1212 printf("Unaligned read of sector : possible panic() on some systems avoided\n");
1213 return EIO;
1214 }
1215
1216 sector_size = disc->sector_size;
1217
1218 /* read one UDF sector at a physical address specified in UDF_SECTOR size units */
1219 size = num_sectors * disc->sector_size;
1220 size_read = 0;
1221 bzero(result, size); /* just in case */ /* has to go? */
1222
1223 assert(sector_size);
1224 assert(num_sectors <= 0xffff);
1225
1226 /* statistics and cache control */
1227 if (disc->am_writing) {
1228 disc->switchings++;
1229 /* XXX how about pseudo-overwrite? is this nessisary then too ? XXX */
1230 if (disc->sequential) {
1231 /*
1232 * we need to synchronise the write caches before we
1233 * are allowed to read from the disc again.
1234 */
1235 error = udf_discinfo_synchronise_caches(disc);
1236 while (error) {
1237 printf("udf_discinfo: failed to sync caches, retrying\n");
1238 error = udf_discinfo_synchronise_caches(disc);
1239 }
1240 /* we need to update our NWA's after the sync on sequentials */
1241 udf_get_disc_info(disc);
1242 }
1243 /* mark reading access only */
1244 disc->am_writing = 0;
1245 }
1246
1247 error = 0;
1248 DEBUG(printf("\r%08d : %s; read %d bytes\n", (int) sector, what, size));
1249 while (num_sectors) {
1250 switch (disc->devdrv_class & UDF_DEVDRV_CLASS) {
1251 case UDF_DEVDRV_CLASS_CD :
1252 case UDF_DEVDRV_CLASS_DVD :
1253 /*
1254 * Use a SCSI command to read it so we can go past the last session;
1255 * allthough READ (12) is available, some older CD-ROM
1256 * devices only want to do READ (10).
1257 */
1258
1259 /* limited by MAXPHYS, taking 64kb as limitation */
1260 chunk = MIN(64*1024 / sector_size, num_sectors);
1261 size_read = chunk * sector_size; /* definition */
1262 skipped = session = 0;
1263
1264 bzero(cmd, SCSI_CMD_LEN);
1265 cmd[0] = 0x28; /* READ (10) command */
1266 cmd[1] = 0; /* normal access */
1267 cmd[2] = (sector >> 24) & 0xff;
1268 cmd[3] = (sector >> 16) & 0xff;
1269 cmd[4] = (sector >> 8) & 0xff;
1270 cmd[5] = (sector ) & 0xff;
1271 cmd[6] = 0; /* reserved */
1272 cmd[7] = (chunk >> 8) & 0xff; /* MSB transfer */
1273 cmd[8] = (chunk ) & 0xff; /* number of logical block(s) */
1274 cmd[9] = 0; /* control */
1275 do {
1276 error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 10, result, size_read - skipped, 30000, &sense);
1277 /* TODO: if busy, ask drive how long it'll take to be available again and wait */
1278 if (sense.asc == 4)
1279 usleep(5000);
1280 } while (sense.asc == 4);
1281
1282 if (error) return ENOENT;
1283 break;
1284 default :
1285 /* XXX first and only reference to {p}read() XXX */
1286 if (sector>=0)
1287 size_read = pread(disc->dev->fhandle, result, (uint64_t) num_sectors * sector_size, sector * sector_size);
1288 break;
1289 }
1290 /* statistics */
1291 disc->sectors_read += size_read / sector_size;
1292
1293 /* swap space if requested */
1294 if (disc->bswap_sectors) {
1295 for (pos = 0; pos < size_read;) {
1296 lb = result[pos ];
1297 hb = result[pos+1];
1298 result[pos ] = hb;
1299 result[pos+1] = lb;
1300 pos += 2;
1301 }
1302 }
1303
1304 /* advance */
1305 num_sectors -= size_read / sector_size;
1306 sector += size_read / sector_size;
1307 result += size_read;
1308 if (size_read <= 0) {
1309 UDF_VERBOSE_MAX(
1310 if (what) {
1311 printf("Can't read sectors %d+%d for %s\n", (int) sector, num_sectors, what);
1312 }
1313 );
1314 if (size_read == 0) return ENOENT;
1315 return error;
1316 }
1317 }
1318
1319 return 0; /* flag ok */
1320 }
1321
1322
1323 /* write an extent of sectors to disc */
udf_write_physical_sectors(struct udf_discinfo * disc,off_t sector,uint32_t num_sectors,char * what,uint8_t * source)1324 int udf_write_physical_sectors(struct udf_discinfo *disc, off_t sector, uint32_t num_sectors, char *what, uint8_t *source) {
1325 struct uscsi_sense sense;
1326 scsicmd cmd;
1327 int trans_length, size, size_written, chunk;
1328 uint32_t sector_size;
1329 uint8_t *buffer;
1330 int lb, hb, pos, error;
1331
1332 /* if (!disc->udf_recording) return ENODEV; */
1333
1334 /* protect us */
1335 if (((long) source) & 3) {
1336 printf("Unaligned write of sector : possible panic() on some systems avoided\n");
1337 return EIO;
1338 }
1339
1340 sector_size = disc->sector_size;
1341
1342 /* XXX clean up XXX */
1343 assert(sector_size);
1344 assert(num_sectors <= 0xffff); /* compatible with WRITE (10)? */
1345
1346 DEBUG(printf("\r%08d : %s ;WRITE %d bytes\n", (int) sector, what, num_sectors * sector_size));
1347
1348 /* swap space if requested */
1349 buffer = source;
1350 if (disc->bswap_sectors) {
1351 size = num_sectors * sector_size;
1352 buffer = malloc(num_sectors * sector_size);
1353 for (pos = 0; pos < size;) {
1354 lb = source[pos ];
1355 hb = source[pos+1];
1356 buffer[pos ] = hb;
1357 buffer[pos+1] = lb;
1358 pos += 2;
1359 }
1360 }
1361
1362 error = 0;
1363 while (num_sectors) {
1364 size_written = 0;
1365
1366 switch (disc->devdrv_class & UDF_DEVDRV_CLASS) {
1367 case UDF_DEVDRV_CLASS_CD :
1368 case UDF_DEVDRV_CLASS_DVD :
1369 /*
1370 * Use WRITE (12) command to write to the disc; we
1371 * might have to downgrade later to using WRITE (10)
1372 * on older discs though :-/
1373 */
1374
1375 /* limited by MAXPHYS, taking 64kb as limitation */
1376 chunk = MIN(64*1024 / sector_size, num_sectors); /* in sectors */
1377 trans_length = chunk; /* in sectors */
1378 bzero(cmd, SCSI_CMD_LEN);
1379 cmd[ 0] = 0xAA; /* WRITE (12) */
1380 cmd[ 1] = 0; /* no force unit access */
1381 cmd[ 2] = (sector >> 24) & 0xff;
1382 cmd[ 3] = (sector >> 16) & 0xff;
1383 cmd[ 4] = (sector >> 8) & 0xff;
1384 cmd[ 5] = (sector ) & 0xff;
1385 cmd[ 6] = (trans_length >> 24) & 0xff; /* MSB */
1386 cmd[ 7] = (trans_length >> 16) & 0xff;
1387 cmd[ 8] = (trans_length >> 8) & 0xff;
1388 cmd[ 9] = (trans_length ) & 0xff; /* LSB */
1389 cmd[10] = 0; /* no streaming */
1390 cmd[11] = 0; /* control */
1391 do {
1392 error = uscsi_command(SCSI_WRITECMD, disc->dev, cmd, 12, buffer, trans_length * sector_size, 30000, &sense);
1393 /* TODO: if busy, ask drive how long it'll take to be available again and wait */
1394 if (sense.asc == 4)
1395 usleep(5000);
1396 } while (sense.asc == 4);
1397
1398 /* write one UDF sector at a physical address specified in UDF_SECTOR size units */
1399 size = trans_length * sector_size;
1400 size_written = error ? 0 : size;
1401 break;
1402 default :
1403 /* XXX first and only reference to {p}write() XXX */
1404 DEBUG(printf("udf_discop: pwrite %"PRIu64" + %d\n", (uint64_t) sector * sector_size, (int) num_sectors * sector_size));
1405 /* write one UDF sector at a physical address specified in UDF_SECTOR size units */
1406 size = num_sectors * sector_size;
1407 size_written = pwrite(disc->dev->fhandle, buffer, (uint64_t) num_sectors * sector_size, sector * sector_size);
1408 if (size_written < 0)
1409 size_written = 0;
1410 break;
1411 }
1412
1413 /* free our copy if we created one */
1414 if (buffer != source)
1415 free(buffer);
1416
1417 /* statistics */
1418 disc->sectors_written += size_written / sector_size;
1419 if (!disc->am_writing) disc->switchings++;
1420 disc->am_writing = 1;
1421
1422 num_sectors -= size_written / sector_size;
1423 sector += size_written / sector_size;
1424 buffer += size_written;
1425 if ((size_written < size) || error) {
1426 DEBUG(if (error) printf("Writing %s at sectors %d+%d failed\n", what, (int) sector, num_sectors));
1427 return EIO;
1428 }
1429 }
1430
1431 return 0;
1432 }
1433
1434
1435 /* End of udf_discinfo.c */
1436
1437