1 /* -*- C -*-
2 Copyright (C) 2009 Thomas Schmitt <scdbackup@gmx.net>
3 Copyright (C) 2010, 2012-2013, 2017 Rocky Bernstein <rocky@gnu.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /*
20 Regression test for MMC commands involving read/write access.
21 */
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #define __CDIO_CONFIG_H__ 1
25 #endif
26
27 #ifdef HAVE_STDIO_H
28 #include <stdio.h>
29 #endif
30 #ifdef HAVE_SYS_TYPES_H
31 #include <sys/types.h>
32 #endif
33 #ifdef HAVE_STDLIB_H
34 #include <stdlib.h>
35 #endif
36 #ifdef HAVE_UNISTD_H
37 #include <unistd.h>
38 #endif
39 #ifdef HAVE_STRING_H
40 #include <string.h>
41 #endif
42 #ifdef _WIN32
43 # undef HAVE_SLEEP
44 #endif
45 #if !defined(HAVE_SLEEP)
46 # if defined(_WIN32)
47 # include <windows.h>
48 # define sleep(s) Sleep(1000*s)
49 # elif defined(HAVE_USLEEP)
50 # define sleep(s) usleep(1000000*s)
51 # else
52 # define sleep(s) { int i; for(i=0; i<=1000*s; i++); }
53 # endif
54 #endif
55
56 #include <cdio/cdio.h>
57 #include <cdio/logging.h>
58 #include <cdio/mmc_cmds.h>
59
60 #define SKIP_TEST 77
61
62 /* gcc may warn if no prototypes are given before function definition */
63
64 static int handle_outcome(CdIo_t *p_cdio, int i_status,
65 unsigned int *pi_sense_avail,
66 cdio_mmc_request_sense_t * p_sense_reply,
67 unsigned int i_flag);
68
69 static int load_eject(CdIo_t *p_cdio, unsigned int *pi_sense_avail,
70 cdio_mmc_request_sense_t * p_sense_reply,
71 unsigned int i_flag);
72
73 static void print_status_sense(int i_status, int sense_valid,
74 cdio_mmc_request_sense_t *,
75 unsigned int i_flag);
76
77 static int test_eject_load_cycle(CdIo_t *p_cdio, unsigned int i_flag);
78
79 static int test_eject_test_load(CdIo_t *p_cdio, unsigned int i_flag);
80
81 static int test_mode_select(CdIo_t *p_cdio,
82 unsigned int *pi_sense_avail,
83 cdio_mmc_request_sense_t *p_sense_reply,
84 unsigned char *p_buf, unsigned int i_size,
85 unsigned int i_flag);
86
87 static int mode_sense(CdIo_t *p_cdio, unsigned int *pi_sense_avail,
88 cdio_mmc_request_sense_t * p_sense_reply,
89 unsigned int i_page_code,
90 unsigned int subpage_code, int i_alloc_len,
91 unsigned char *buf, int *i_size,
92 unsigned int i_flag);
93
94 static int test_unit_ready(CdIo_t *p_cdio,
95 unsigned int *pi_sense_avail,
96 cdio_mmc_request_sense_t * p_sense_reply,
97 unsigned int i_flag);
98
99 static int test_rwr_mode_page(CdIo_t *p_cdio, unsigned int i_flag);
100
101 static int test_write(char *psz_drive_path, unsigned int i_flag);
102
103 static int wait_for_drive(CdIo_t *p_cdio, unsigned int max_tries, unsigned int i_flag);
104
105 /* ------------------------- Helper functions ---------------------------- */
106
107
108 /* @param i_flag bit0= verbose
109 */
110 static int
handle_outcome(CdIo_t * p_cdio,driver_return_code_t i_status,unsigned int * pi_sense_avail,cdio_mmc_request_sense_t * p_sense_reply,unsigned int i_flag)111 handle_outcome(CdIo_t *p_cdio, driver_return_code_t i_status,
112 unsigned int *pi_sense_avail,
113 cdio_mmc_request_sense_t * p_sense_reply,
114 unsigned int i_flag)
115 {
116 cdio_mmc_request_sense_t *p_temp_sense_reply = NULL;
117 *pi_sense_avail = mmc_last_cmd_sense(p_cdio, &p_temp_sense_reply);
118 print_status_sense(i_status, *pi_sense_avail, p_temp_sense_reply, i_flag & 1);
119 if (18 <= *pi_sense_avail) {
120 memset(p_sense_reply, 0, sizeof(cdio_mmc_request_sense_t));
121 memcpy(p_sense_reply, p_temp_sense_reply, sizeof(cdio_mmc_request_sense_t));
122 } else
123 memset(p_sense_reply, 0, sizeof(cdio_mmc_request_sense_t));
124 cdio_free(p_temp_sense_reply);
125 return i_status;
126 }
127
128
129 /**
130 @param flag bit0= verbose
131 */
132 static void
print_status_sense(int i_status,int sense_valid,cdio_mmc_request_sense_t * p_sense_reply,unsigned int i_flag)133 print_status_sense(int i_status, int sense_valid,
134 cdio_mmc_request_sense_t *p_sense_reply,
135 unsigned int i_flag)
136 {
137 if (!(i_flag & 1))
138 return;
139 printf("return= %d , sense(%d)", i_status, sense_valid);
140 if (sense_valid >= 14)
141 printf(": KEY=%s (%1.1X), ASC= %2.2X , ASCQ= %2.2X",
142 mmc_sense_key2str[p_sense_reply->sense_key],
143 p_sense_reply->sense_key,
144 p_sense_reply->asc,
145 p_sense_reply->ascq);
146 printf("\n");
147 }
148
149
150 /* --------------------------- MMC commands ------------------------------ */
151
152
153 /* OBTRUSIVE. PHYSICAL EFFECT: DANGER OF HUMAN INJURY */
154 /**
155 @param i_flag bit0= verbose
156 bit1= Asynchronous operation
157 bit2= Load (else Eject)
158 @return return value of mmc_run_cmd()
159 */
160 static int
load_eject(CdIo_t * p_cdio,unsigned int * pi_sense_avail,cdio_mmc_request_sense_t * p_sense_reply,unsigned int i_flag)161 load_eject(CdIo_t *p_cdio, unsigned int *pi_sense_avail,
162 cdio_mmc_request_sense_t *p_sense_reply,
163 unsigned int i_flag)
164 {
165 int i_status;
166 bool b_eject = !!(i_flag & 4);
167 bool b_immediate = !!(i_flag & 2);
168
169 i_status = mmc_start_stop_unit(p_cdio, b_eject, b_immediate, 0, 0);
170
171 if (i_flag & 1)
172 printf("load_eject(0x%X) ... ", i_flag);
173
174 return handle_outcome(p_cdio, i_status, pi_sense_avail, p_sense_reply,
175 i_flag & 1);
176 }
177
178
179 /* BARELY OBTRUSIVE: MIGHT RUIN A SIMULTANEOUS BURNING OPERATION ON THE DRIVE */
180 /**
181 Fetch a mode page or a part of it from the drive.
182 @param i_alloc_len The number of bytes to be requested from the drive and to
183 be copied into parameter buf.
184 This has to include the 8 bytes of header and may not
185 be less than 10.
186 @param p_buf Will contain at most alloc_len many bytes. The first 8 are
187 a Mode Parameter Header as of SPC-3 7.4.3, table 240.
188 The further bytes are the mode page, typically as of
189 MMC-5 7.2. There are meanwhile deprecated mode pages which
190 appear only in older versions of MMC.
191 @param i_size Will return the number of actually read bytes resp. the
192 number of available bytes. See flag bit1.
193 @param i_flag bit0= verbose
194 bit1= Peek mode:
195 Reply number of available bytes in *i_size and not
196 the number of actually read bytes.
197 @return return value of mmc_run_cmd(),
198 or other driver_return_code_t
199 */
200 static driver_return_code_t
mode_sense(CdIo_t * p_cdio,unsigned int * pi_sense_avail,cdio_mmc_request_sense_t * p_sense_reply,unsigned int i_page_code,unsigned int subpage_code,int i_alloc_len,unsigned char * p_buf,int * pi_size,unsigned int i_flag)201 mode_sense(CdIo_t *p_cdio, unsigned int *pi_sense_avail,
202 cdio_mmc_request_sense_t *p_sense_reply,
203 unsigned int i_page_code, unsigned int subpage_code, int i_alloc_len,
204 unsigned char *p_buf, int *pi_size, unsigned int i_flag)
205 {
206 driver_return_code_t i_status;
207
208 if (i_alloc_len < 10)
209 return DRIVER_OP_BAD_PARAMETER;
210
211 if (i_flag & 1)
212 printf("mode_sense(0x%X, %X, %d) ... ",
213 i_page_code, subpage_code, i_alloc_len);
214
215 i_status = mmc_mode_sense_10(p_cdio, p_buf, i_alloc_len, i_page_code);
216 handle_outcome(p_cdio, i_status, pi_sense_avail, p_sense_reply, i_flag & 1);
217 if (DRIVER_OP_SUCCESS != i_status)
218 return i_status;
219 if (i_flag & 2)
220 *pi_size = p_buf[9] + 10; /* MMC-5 7.2.3 */
221 else
222 *pi_size = p_buf[0] * 256 + p_buf[1] + 2; /* SPC-3 7.4.3, table 240 */
223 return i_status;
224 }
225
226
227 /* OBTRUSIVE. RUINS A SIMULTANEOUS BURNING OPERATION ON THE DRIVE
228 and might return minor failure with -ROM drives */
229 /**
230 Send a mode page to the drive.
231 @param buf Contains the payload bytes. The first 8 shall be a Mode
232 Parameter Header as of SPC-3 7.4.3, table 240.
233 The further bytes are the mode page, typically as of
234 MMC-5 7.2. There are meanwhile deprecated mode pages which
235 appear only in older versions of MMC.
236 @param i_size The number of bytes in buf.
237 @param flag bit0= verbose
238 @return return value of mmc_run_cmd(),
239 or other driver_return_code_t
240 */
241 static int
test_mode_select(CdIo_t * p_cdio,unsigned int * pi_sense_avail,cdio_mmc_request_sense_t * p_sense_reply,unsigned char * p_buf,unsigned int i_size,unsigned int i_flag)242 test_mode_select(CdIo_t *p_cdio,
243 unsigned int *pi_sense_avail,
244 cdio_mmc_request_sense_t *p_sense_reply,
245 unsigned char *p_buf, unsigned int i_size, unsigned int i_flag)
246 {
247 int i_status, i;
248
249 if (i_size < 10)
250 return DRIVER_OP_BAD_PARAMETER;
251
252 if (i_flag & 1) {
253 printf("-- test_mode_select to drive: %d bytes\n", i_size);
254 for (i = 0; i < i_size; i++) {
255 printf("%2.2X ", (unsigned int) p_buf[i]);
256 if ((i % 20) == 19)
257 printf("\n");
258 }
259 if ((i % 20))
260 printf("\n");
261 }
262
263 if (i_flag & 1)
264 printf("-- test_mode_select(0x%X, %d, %d) ... ",
265 (unsigned int) p_buf[8], (unsigned int) p_buf[9], i_size);
266 i_status = mmc_mode_select_10(p_cdio, p_buf, i_size, 0x10, 10000);
267 return handle_outcome(p_cdio, i_status, pi_sense_avail, p_sense_reply,
268 i_flag & 1);
269 }
270
271 /* UNOBTRUSIVE */
272 /**
273 @param pi_sense_avail Number of available sense bytes
274 (18 get copied if all 18 exist)
275 @param p_sense_reply eventual sense bytes
276 @param i_flag bit0= verbose
277 @return return value of mmc_run_cmd()
278 */
279 static int
test_unit_ready(CdIo_t * p_cdio,unsigned int * pi_sense_avail,cdio_mmc_request_sense_t * p_sense_reply,unsigned int i_flag)280 test_unit_ready(CdIo_t *p_cdio,
281 unsigned int *pi_sense_avail,
282 cdio_mmc_request_sense_t *p_sense_reply,
283 unsigned int i_flag)
284 {
285 int i_status;
286
287 if (i_flag & 1)
288 printf("-- test_unit_ready ... ");
289 i_status = mmc_test_unit_ready(p_cdio, 0);
290
291 return handle_outcome(p_cdio, i_status, pi_sense_avail, p_sense_reply,
292 i_flag & 1);
293 }
294
295
296 /* --------------------------- Larger gestures ----------------------------- */
297
298
299 /* UNOBTRUSIVE */
300 /**
301 Watch drive by test unit ready loop until ready, no media or timeout.
302 @param flag bit0= verbose
303 bit1= expect media (do not end on no-media sense)
304 @return 1= all seems well , 0= minor failure , -1= severe failure
305 */
306 static int
wait_for_drive(CdIo_t * p_cdio,unsigned int i_max_tries,unsigned int i_flag)307 wait_for_drive(CdIo_t *p_cdio, unsigned int i_max_tries, unsigned int i_flag)
308 {
309 int i_ret, i;
310 unsigned int i_sense_avail;
311 cdio_mmc_request_sense_t sense_reply;
312
313 for (i = 0; i < i_max_tries; i++) {
314 i_ret = test_unit_ready(p_cdio, &i_sense_avail, &sense_reply, !!(i_flag & 1));
315 if (i_ret == 0) /* Unit is ready */
316 return 1;
317 if (i_sense_avail < 18)
318 return -1;
319 if (2 == sense_reply.sense_key && 0x04 == sense_reply.asc) {
320
321 /* Not ready */;
322
323 } else if (6 == sense_reply.sense_key && 0x28 == sense_reply.asc &&
324 0 == sense_reply.ascq) {
325
326 /* Media change notice = try again */;
327
328 } else if (2 == sense_reply.sense_key && 0x3a == sense_reply.asc) {
329
330 /* Medium not present */;
331
332 if (!(i_flag & 2))
333 return 1;
334 } else if (0 == sense_reply.sense_key && 0 == sense_reply.asc) {
335
336 /* Error with no sense */;
337
338 return -1;
339 break;
340 } else {
341
342 /* Other error */;
343
344 return 0;
345 }
346 sleep(1);
347 }
348 fprintf(stderr, "wait_for_drive: Drive not ready after %d retries\n",
349 i_max_tries);
350 return -1;
351 }
352
353
354 /* OBTRUSIVE. Opens and closes drive door - watch your fingers! */
355 /**
356 Eject, wait, load asynchronously, and watch by test unit ready loop.
357 @param i_flag bit0= verbose
358 bit1= expect media (do not end on no-media sense)
359 @return 1= all seems well , 0= minor failure , -1= severe failure
360 */
361 static int
test_eject_load_cycle(CdIo_t * p_cdio,unsigned int i_flag)362 test_eject_load_cycle(CdIo_t *p_cdio, unsigned int i_flag)
363 {
364 int i_ret;
365 unsigned int i_sense_avail;
366 cdio_mmc_request_sense_t sense_reply;
367
368 /* Eject synchronously */
369 printf("test_eject_load_cycle: WARNING: EJECTING THE TRAY !\n");
370 sleep(2);
371 load_eject(p_cdio, &i_sense_avail, &sense_reply, 0 | (i_flag & 1));
372
373 printf("test_eject_load_cycle: waiting for 5 seconds. DO NOT TOUCH THE TRAY !\n");
374 sleep(3);
375
376 /* Load asynchronously */
377 printf("test_eject_load_cycle: WARNING: LOADING THE TRAY !\n");
378 sleep(2);
379 load_eject(p_cdio, &i_sense_avail, &sense_reply, 4 | 2 | (i_flag & 1));
380
381 /* Wait for drive attention */
382 i_ret = wait_for_drive(p_cdio, 30, i_flag & 3);
383 return i_ret;
384 }
385
386
387 /* OBTRUSIVE , PHYSICAL EFFECT , DANGER OF HUMAN INJURY */
388 /**
389 Eject, wait, test, load. All synchronously.
390 @param flag bit0= verbose
391 @return 1= all seems well , 0= minor failure , -1= severe failure
392 */
393 static int
test_eject_test_load(CdIo_t * p_cdio,unsigned int i_flag)394 test_eject_test_load(CdIo_t *p_cdio, unsigned int i_flag)
395 {
396 int i_ret;
397 unsigned int i_sense_avail;
398 cdio_mmc_request_sense_t sense_reply;
399
400 /* Eject synchronously */
401 printf("test_eject_test_load: WARNING: EJECTING THE TRAY !\n");
402 sleep(2);
403 load_eject(p_cdio, &i_sense_avail, &sense_reply, 0 | (i_flag & 1));
404
405 printf("test_eject_test_load: waiting for 5 seconds. DO NOT TOUCH THE TRAY !\n");
406 sleep(3);
407
408 i_ret = test_unit_ready(p_cdio, &i_sense_avail, &sense_reply, i_flag & 1);
409 if (i_ret == 0) {
410 fprintf(stderr,
411 "test_eject_test_load: Drive ready although tray ejected.\n");
412 fprintf(stderr,
413 "test_eject_test_load: Test aborted. Tray will stay ejected.\n");
414 return -1;
415 }
416 if (i_ret == 0 || i_sense_avail < 18) {
417 fprintf(stderr,
418 "test_eject_test_load: Only %d sense reply bytes returned. Expected >= 18.\n",
419 i_sense_avail);
420 fprintf(stderr,
421 "test_eject_test_load: Test aborted. Tray will stay ejected.\n");
422 return -1;
423 }
424
425 /* Load synchronously */
426 fprintf(stderr,
427 "test_eject_test_load: WARNING: LOADING THE TRAY !\n");
428 sleep(2);
429 load_eject(p_cdio, &i_sense_avail, &sense_reply, 4 | (i_flag & 1));
430
431 return 1;
432 }
433
434
435 /* OBTRUSIVE */
436 /**
437 Read Mode Page 05h "Write Parameters", change a value, write the page,
438 check effect, restore old value, check again.
439 @param flag bit0= verbose
440 @return 1= all seems well , 0= minor failure , -1= severe failure
441 */
442 static int
test_rwr_mode_page(CdIo_t * p_cdio,unsigned int i_flag)443 test_rwr_mode_page(CdIo_t *p_cdio, unsigned int i_flag)
444 {
445 int i_ret;
446 unsigned int i_sense_avail = 0;
447 int page_code = 5, subpage_code = 0, i_alloc_len, i_size = 0;
448 int write_type, final_return = 1, new_write_type, old_i_size;
449 cdio_mmc_request_sense_t sense_reply;
450 unsigned char buf[265], old_buf[265]; /* page size is max. 255 + 10 */
451 static char w_types[4][8] = {"Packet", "TAO", "SAO", "Raw"};
452
453 memset(buf, 0, sizeof(buf));
454
455 i_alloc_len = 10;
456 i_ret = mode_sense(p_cdio, &i_sense_avail, &sense_reply,
457 page_code, subpage_code, i_alloc_len,
458 buf, &i_size, 2 | (i_flag & 1));
459 if (i_ret != 0) {
460 fprintf(stderr,
461 "-- test_rwr_mode_page: Cannot obtain mode page 05h.\n");
462 return 0;
463 }
464 i_alloc_len = (i_size <= sizeof(buf)) ? i_size : sizeof(buf);
465 i_ret = mode_sense(p_cdio, &i_sense_avail, &sense_reply,
466 page_code, subpage_code, i_alloc_len,
467 buf, &i_size, (i_flag & 1));
468 if (i_ret != 0) {
469 fprintf(stderr,
470 "-- test_rwr_mode_page: Cannot obtain mode page 05h.\n");
471 return 0;
472 }
473 memcpy(old_buf, buf, sizeof(buf));
474 old_i_size = i_size;
475
476 write_type = buf[10] & 0x0f;
477 if (i_flag & 1)
478 printf("test_rwr_mode_page: Write type = %d (%s)\n",
479 write_type, write_type < 4 ? w_types[write_type] : "Reserved");
480
481 /* Choose a conservative CD writer setting.
482 */
483 memset(buf, 0, 8);
484 if (write_type == 1) { /* is TAO -> make SAO */
485 buf[10] = (buf[10] & 0xf0) | 2; /* SAO */
486 new_write_type = 2;
487 } else {
488 buf[10] = (buf[10] & 0xf0) | 1; /* TAO */
489 new_write_type = 1;
490 }
491 buf[11] = 4; /* Track Mode 4, no multi-session,
492 variable Packet size */
493 buf[12] = 8; /* Data Block Type : CD-ROM Mode 1 */
494 buf[16] = 0; /* Session Format : "CD-DA or CD-ROM" */
495
496 i_ret = test_mode_select(p_cdio, &i_sense_avail, &sense_reply,
497 buf, i_size, i_flag & 1);
498 if (i_ret != 0) {
499 fprintf(stderr,
500 "-- test_rwr_mode_page: Cannot set mode page 05h.\n");
501 if (DRIVER_OP_NOT_PERMITTED == i_ret) {
502 fprintf(stderr,
503 "test_rwr_mode_page: DRIVER_OP_NOT_PERMITTED with MODE SELECT.\n");
504 return -1;
505 }
506 return 0;
507 }
508
509 /* Read mode page and check whether effect visible in buf[10] */
510 i_ret = mode_sense(p_cdio, &i_sense_avail, &sense_reply,
511 page_code, subpage_code, i_alloc_len,
512 buf, &i_size, (i_flag & 1));
513 if (0 != i_ret) {
514 fprintf(stderr, "test_rwr_mode_page: Cannot obtain mode page 05h.\n");
515 final_return = final_return > 0 ? 0 : final_return;
516 } else if ((buf[10] & 0xf) != new_write_type) {
517 fprintf(stderr,
518 "test_rwr_mode_page: Mode page did not get into effect. (expected %d, got %d)\n",
519 new_write_type, buf[10] & 0xf);
520 /* One of my DVD burners does this if no media is loaded */
521 final_return = final_return > 0 ? 0 : final_return;
522 }
523
524 /* Restore old mode page */
525 i_ret = test_mode_select(p_cdio, &i_sense_avail, &sense_reply,
526 old_buf, old_i_size, i_flag & 1);
527 if (0 != i_ret) {
528 fprintf(stderr, "test_rwr_mode_page: Cannot set mode page 05h.\n");
529 if (i_ret == DRIVER_OP_NOT_PERMITTED) {
530 fprintf(stderr,
531 "test_rwr_mode_page: DRIVER_OP_NOT_PERMITTED with MODE SELECT.\n");
532 return -1;
533 }
534 final_return = final_return > 0 ? 0 : final_return;
535 }
536
537 /* Read mode page and check whether old_buf is in effect again */
538 i_ret = mode_sense(p_cdio, &i_sense_avail, &sense_reply,
539 page_code, subpage_code, i_alloc_len,
540 buf, &i_size, (i_flag & 1));
541 if (0 != i_ret) {
542 fprintf(stderr, "test_rwr_mode_page: Cannot obtain mode page 05h.\n");
543 return final_return > 0 ? 0 : final_return;
544 } else if (memcmp(buf, old_buf, i_size) != 0) {
545 fprintf(stderr,
546 "test_rwr_mode_page: Mode page was not restored to old state.\n");
547 final_return = final_return > 0 ? -1 : final_return;
548 }
549 if (i_flag & 1)
550 printf("test_rwr_mode_page: Mode page 2Ah restored to previous state\n");
551 return final_return;
552 }
553
554
555 /* ----------- Test of MMC driver enhancements , december 2009 ------------- */
556
557
558 /* OBTRUSIVE */
559 /**
560 This function bundles tests for the capability to perform MMC commands
561 of payload direction SCSI_MMC_DATA_WRITE and to detect the sense reply of
562 MMC commands, which indicates error causes or important drive events.
563
564 The default configuration is not very obtrusive to the drive, although the
565 drive should not be used for other operations at the same time.
566 There are static variables in this function which enable additional
567 more obtrusive tests or simulate the lack of write capabilities.
568 See the statements about obtrusiveness and undesired side effects above
569 the descriptions of the single functions.
570
571 @param psz_drive_path a drive address suitable for cdio_open_am()
572 @param flag bit0= verbose
573 @return 0= no severe failure
574 else an proposal for an exit() value is returned
575 */
576 static int
test_write(char * psz_drive_path,unsigned int i_flag)577 test_write(char *psz_drive_path, unsigned int i_flag)
578 {
579 unsigned int i_sense_avail = 0;
580 unsigned int i_sense_valid;
581 int i_ret;
582 bool b_verbose = !!(i_flag & 1);
583 int old_log_level = cdio_loglevel_default;
584 cdio_mmc_request_sense_t sense_reply;
585 CdIo_t *p_cdio;
586
587 /* If true, then the tray will get ejected and loaded again */
588 static bool with_tray_dance = false;
589
590 /* If true, then an asynchronous test loop will wait 30 s for loaded media */
591 static bool test_cycle_with_media = false;
592
593 /* If true, then a lack of w-permission will be emulated by using the
594 insufficient access mode "IOCTL" */
595 static bool emul_lack_of_wperm = false;
596
597 p_cdio = cdio_open_am(psz_drive_path, DRIVER_DEVICE, "MMC_RDWR_EXCL");
598 if (!p_cdio)
599 i_ret = SKIP_TEST - 16;
600 else {
601 const char *psz_access_mode = cdio_get_arg(p_cdio, "access-mode");
602
603 if (0 != strncmp(psz_access_mode,
604 "MMC_RDWR_EXCL", strlen("MMC_RDWR_EXCL"))) {
605 fprintf(stderr,
606 "Got %s; Should get back %s, the access mode requested.\n",
607 psz_access_mode, "MMC_RDWR_EXCL");
608 i_ret = 1; goto ex;
609 }
610
611 /* The further code produces some intentional failures which should not be
612 reported by mmc_run_cmd() as INFO messages.
613 */
614 cdio_loglevel_default = CDIO_LOG_WARN;
615
616 /* Test availability of sense reply in case of unready drive.
617 E.g. if the tray is already ejected.
618 */
619 i_ret = test_unit_ready(p_cdio, &i_sense_avail, &sense_reply, b_verbose);
620 if (0 != i_ret && i_sense_avail < 18) {
621 fprintf(stderr,
622 "Error: Drive not ready. Only %u sense bytes. Expected >= 18.\n",
623 i_sense_avail);
624 i_ret = 2; goto ex;
625 }
626
627 if (emul_lack_of_wperm) { /* To check behavior with lack of w-permission */
628 printf("-- test_write: SIMULATING LACK OF WRITE CAPABILITIES by access mode IOCTL\n");
629 cdio_destroy(p_cdio);
630 p_cdio = cdio_open_am(psz_drive_path, DRIVER_DEVICE, "IOCTL");
631 }
632
633
634 /* Test write permission */ /* Try whether a mode page 2Ah can be set */
635 i_ret = test_rwr_mode_page(p_cdio, b_verbose);
636 if (i_ret <= 0) {
637 if (i_ret < 0) {
638 fprintf(stderr, "Error: test_rwr_mode_page() had severe failure.\n");
639 i_ret = 3; goto ex;
640 }
641 printf("-- Warning: test_rwr_mode_page() had minor failure.\n");
642 }
643
644
645 if (with_tray_dance) {
646 /* More surely provoke a non-trivial sense reply */
647 if (test_cycle_with_media) {
648 /* Eject, wait, load, watch by test unit ready loop */
649 i_ret = test_eject_load_cycle(p_cdio, 2 | b_verbose);
650 if (i_ret <= 0) {
651 if (i_ret < 0) {
652 fprintf(stderr,
653 "Error: test_eject_load_cycle() had severe failure.\n");
654 i_ret = 4; goto ex;
655 }
656 printf("Warning: test_eject_load_cycle() had minor failure.\n");
657 }
658 } else {
659 /* Eject, test for proper unreadiness, load */
660 i_ret = test_eject_test_load(p_cdio, b_verbose);
661 if (i_ret <= 0) {
662 if (i_ret < 0) {
663 fprintf(stderr,
664 "Error: test_eject_test_load() had severe failure.\n");
665 i_ret = 5; goto ex;
666 }
667 printf("Warning: test_eject_test_load() had minor failure.\n");
668 }
669 /* Wait for drive attention */
670 wait_for_drive(p_cdio, 15, 2 | b_verbose);
671 }
672 }
673
674 /* How are we, finally ? */
675 i_ret = test_unit_ready(p_cdio, &i_sense_valid, &sense_reply, b_verbose);
676 if ((i_flag & 1) && 0 != i_ret && 2 == sense_reply.sense_key &&
677 0x3a == sense_reply.asc)
678 fprintf(stderr, "test_unit_ready: Note: No loaded media detected.\n");
679 i_ret = 0;
680 }
681
682 ex:;
683 cdio_loglevel_default = old_log_level;
684 cdio_destroy(p_cdio);
685 return i_ret;
686 }
687
688 /* --------------------------- main ----------------------------- */
689
690 int
main(int argc,const char * argv[])691 main(int argc, const char *argv[])
692 {
693 CdIo_t *p_cdio;
694 char **ppsz_drives=NULL;
695 int ret;
696 int exitrc = 0;
697 bool b_verbose = (argc > 1);
698
699 cdio_loglevel_default = b_verbose ? CDIO_LOG_DEBUG : CDIO_LOG_WARN;
700
701 ppsz_drives = cdio_get_devices(DRIVER_DEVICE);
702 if (!ppsz_drives) {
703 printf("Can't find a CD-ROM drive. Skipping test.\n");
704 exit(SKIP_TEST);
705 }
706
707 p_cdio = cdio_open(ppsz_drives[0], DRIVER_DEVICE);
708 if (p_cdio) {
709 const char *psz_have_mmc = cdio_get_arg(p_cdio, "mmc-supported?");
710
711 if ( psz_have_mmc
712 && 0 == strncmp("true", psz_have_mmc, sizeof("true")) ) {
713
714 /* Test the MMC enhancements of version 0.83 in december 2009 */
715 ret = test_write(ppsz_drives[0],
716 cdio_loglevel_default == CDIO_LOG_DEBUG);
717 if (ret != 0) exit(ret + 16);
718 }
719
720 cdio_destroy(p_cdio);
721
722 } else {
723 fprintf(stderr, "cdio_open('%s') failed\n", ppsz_drives[0]);
724 exit(2);
725 }
726
727 cdio_free_device_list(ppsz_drives);
728
729 return exitrc;
730 }
731