1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <sys/types.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30
31 #include "transport.h"
32 #include "mmc.h"
33 #include "util.h"
34 #include "main.h"
35
36 int uscsi_error;
37
38 int
test_unit_ready(int fd)39 test_unit_ready(int fd)
40 {
41 struct uscsi_cmd *scmd;
42
43 scmd = get_uscsi_cmd();
44 scmd->uscsi_flags = USCSI_SILENT;
45 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
46 /* give length of cdb structure */
47 scmd->uscsi_cdblen = 6;
48 if ((uscsi_error = uscsi(fd, scmd)) < 0)
49 return (0);
50 return (1);
51 }
52
53 int
inquiry(int fd,uchar_t * inq)54 inquiry(int fd, uchar_t *inq)
55 {
56 struct uscsi_cmd *scmd;
57
58 scmd = get_uscsi_cmd();
59 scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
60 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
61 scmd->uscsi_cdb[0] = INQUIRY_CMD;
62 scmd->uscsi_cdb[4] = INQUIRY_DATA_LENGTH;
63 scmd->uscsi_cdblen = 6;
64 scmd->uscsi_bufaddr = (char *)inq;
65 scmd->uscsi_buflen = INQUIRY_DATA_LENGTH;
66 if ((uscsi_error = uscsi(fd, scmd)) < 0)
67 return (0);
68 return (1);
69 }
70
71 int
read_capacity(int fd,uchar_t * capbuf)72 read_capacity(int fd, uchar_t *capbuf)
73 {
74 struct uscsi_cmd *scmd;
75
76 scmd = get_uscsi_cmd();
77 scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
78 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
79 scmd->uscsi_cdb[0] = READ_CAP_CMD;
80 scmd->uscsi_cdblen = 10;
81 scmd->uscsi_bufaddr = (char *)capbuf;
82 scmd->uscsi_buflen = 8;
83 if ((uscsi_error = uscsi(fd, scmd)) < 0)
84 return (0);
85 return (1);
86 }
87
88 int
mode_sense(int fd,uchar_t pc,int dbd,int page_len,uchar_t * buffer)89 mode_sense(int fd, uchar_t pc, int dbd, int page_len, uchar_t *buffer)
90 {
91 struct uscsi_cmd *scmd;
92
93 scmd = get_uscsi_cmd();
94 scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
95 scmd->uscsi_buflen = page_len;
96 scmd->uscsi_bufaddr = (char *)buffer;
97 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
98 scmd->uscsi_cdblen = 0xa;
99 scmd->uscsi_cdb[0] = MODE_SENSE_10_CMD;
100 if (dbd) {
101 /* don't return any block descriptors */
102 scmd->uscsi_cdb[1] = 0x8;
103 }
104 /* the page code we want */
105 scmd->uscsi_cdb[2] = pc;
106 /* allocation length */
107 scmd->uscsi_cdb[7] = (page_len >> 8) & 0xff;
108 scmd->uscsi_cdb[8] = page_len & 0xff;
109
110 if ((uscsi_error = uscsi(fd, scmd)) < 0)
111 return (0);
112 return (1);
113 }
114
115 int
mode_select(int fd,int page_len,uchar_t * buffer)116 mode_select(int fd, int page_len, uchar_t *buffer)
117 {
118 struct uscsi_cmd *scmd;
119
120 scmd = get_uscsi_cmd();
121 scmd->uscsi_flags = USCSI_WRITE|USCSI_SILENT;
122 scmd->uscsi_buflen = page_len;
123 scmd->uscsi_bufaddr = (char *)buffer;
124 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
125 scmd->uscsi_cdblen = 0xa;
126
127 /* mode select (10) command */
128 scmd->uscsi_cdb[0] = MODE_SELECT_10_CMD;
129 scmd->uscsi_cdb[1] = 0x10;
130
131 /* parameter list length */
132 scmd->uscsi_cdb[7] = (page_len >> 8) & 0xff;
133 scmd->uscsi_cdb[8] = page_len & 0xff;
134
135 if ((uscsi_error = uscsi(fd, scmd)) < 0)
136 return (0);
137 return (1);
138 }
139
140 int
read_track_info(int fd,int trackno,uchar_t * ti)141 read_track_info(int fd, int trackno, uchar_t *ti)
142 {
143 struct uscsi_cmd *scmd;
144
145 scmd = get_uscsi_cmd();
146 scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
147 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
148 scmd->uscsi_cdb[0] = READ_TRACK_CMD;
149
150 /* tell device we are giving it a track number */
151 scmd->uscsi_cdb[1] = 1;
152
153 /* track number to read */
154 if (trackno == -1)
155 if (device_type == CD_RW) {
156 ((uchar_t *)scmd->uscsi_cdb)[5] = 0xff;
157 } else {
158 /* only 1 track is allowed on DVD media */
159 scmd->uscsi_cdb[1] = 0;
160 ((uchar_t *)scmd->uscsi_cdb)[5] = 0;
161 }
162 else
163 scmd->uscsi_cdb[5] = (uchar_t)trackno;
164
165 scmd->uscsi_cdb[8] = TRACK_INFO_SIZE;
166 scmd->uscsi_cdblen = 10;
167 scmd->uscsi_bufaddr = (char *)ti;
168 scmd->uscsi_buflen = TRACK_INFO_SIZE;
169 if ((uscsi_error = uscsi(fd, scmd)) < 0)
170 return (0);
171 return (1);
172 }
173
174 int
read_toc(int fd,int format,int trackno,int buflen,uchar_t * buf)175 read_toc(int fd, int format, int trackno, int buflen, uchar_t *buf)
176 {
177 struct uscsi_cmd *scmd;
178
179 scmd = get_uscsi_cmd();
180 scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
181 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
182 scmd->uscsi_cdb[0] = READ_TOC_CMD;
183 scmd->uscsi_cdb[2] = format & 0xf;
184 scmd->uscsi_cdb[6] = trackno;
185 scmd->uscsi_cdb[8] = buflen & 0xff;
186 scmd->uscsi_cdb[7] = (buflen >> 8) & 0xff;
187 scmd->uscsi_cdblen = 10;
188 scmd->uscsi_bufaddr = (char *)buf;
189 scmd->uscsi_buflen = buflen;
190 if ((uscsi_error = uscsi(fd, scmd)) < 0)
191 return (0);
192
193 /* Fix for old SONY drives */
194 if ((format == 0) && (buflen == 4) && (buf[0] == 0) && (buf[1] == 2)) {
195 uint16_t toc_size;
196
197 toc_size = (((uint16_t)(buf[3] + 1)) * 8) + 2;
198 load_scsi16(buf, toc_size);
199 }
200 return (1);
201 }
202
203 int
read_header(int fd,uint32_t lba,uchar_t * buf)204 read_header(int fd, uint32_t lba, uchar_t *buf)
205 {
206 struct uscsi_cmd *scmd;
207
208 scmd = get_uscsi_cmd();
209 scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
210 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
211 scmd->uscsi_cdb[0] = READ_HDR_CMD;
212
213 /* Logical block address */
214 load_scsi32(&scmd->uscsi_cdb[2], lba);
215
216 /* allocation length */
217 scmd->uscsi_cdb[8] = 8;
218 scmd->uscsi_cdblen = 10;
219 scmd->uscsi_bufaddr = (char *)buf;
220 scmd->uscsi_buflen = 8;
221 if ((uscsi_error = uscsi(fd, scmd)) < 0)
222 return (0);
223 return (1);
224 }
225
226 int
read_disc_info(int fd,uchar_t * di)227 read_disc_info(int fd, uchar_t *di)
228 {
229 struct uscsi_cmd *scmd;
230
231 scmd = get_uscsi_cmd();
232 scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
233 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
234 scmd->uscsi_cdb[0] = READ_INFO_CMD;
235 scmd->uscsi_cdb[8] = DISC_INFO_BLOCK_SIZE;
236 scmd->uscsi_cdblen = 10;
237 scmd->uscsi_bufaddr = (char *)di;
238 scmd->uscsi_buflen = DISC_INFO_BLOCK_SIZE;
239 if ((uscsi_error = uscsi(fd, scmd)) < 0)
240 return (0);
241 return (1);
242 }
243
244 /* Get information about the Logical Unit's capabilities */
245 int
get_configuration(int fd,uint16_t feature,int bufsize,uchar_t * buf)246 get_configuration(int fd, uint16_t feature, int bufsize, uchar_t *buf)
247 {
248 struct uscsi_cmd *scmd;
249
250 scmd = get_uscsi_cmd();
251 scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
252 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
253
254 /* Set OPERATION CODE in CDB */
255 scmd->uscsi_cdb[0] = GET_CONFIG_CMD;
256
257 /*
258 * Set RT field in CDB, currently need at most one
259 * Feature Descriptor
260 */
261 scmd->uscsi_cdb[1] = 0x2;
262
263 /* Set Starting Feature Number in CDB */
264 scmd->uscsi_cdb[2] = (feature >> 8) & 0xff;
265 scmd->uscsi_cdb[3] = feature & 0xff;
266
267 /* Set Allocation Length in CDB */
268 scmd->uscsi_cdb[7] = (bufsize >> 8) & 0xff;
269 scmd->uscsi_cdb[8] = bufsize & 0xff;
270
271 scmd->uscsi_cdblen = 10;
272 scmd->uscsi_bufaddr = (char *)buf;
273 scmd->uscsi_buflen = bufsize;
274 if ((uscsi_error = uscsi(fd, scmd)) < 0)
275 return (0);
276 return (1);
277 }
278
279 int
read10(int fd,uint32_t start_blk,uint16_t nblk,uchar_t * buf,uint32_t bufsize)280 read10(int fd, uint32_t start_blk, uint16_t nblk, uchar_t *buf,
281 uint32_t bufsize)
282 {
283 struct uscsi_cmd *scmd;
284
285 scmd = get_uscsi_cmd();
286 scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
287 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
288 scmd->uscsi_cdb[0] = READ_10_CMD;
289 load_scsi32(&scmd->uscsi_cdb[2], start_blk);
290 scmd->uscsi_cdb[8] = nblk & 0xff;
291 scmd->uscsi_cdb[7] = (nblk >> 8) & 0xff;
292 scmd->uscsi_cdblen = 10;
293 scmd->uscsi_bufaddr = (char *)buf;
294 scmd->uscsi_buflen = bufsize;
295 if ((uscsi_error = uscsi(fd, scmd)) < 0)
296 return (0);
297 return (1);
298 }
299
300 int
write10(int fd,uint32_t start_blk,uint16_t nblk,uchar_t * buf,uint32_t bufsize)301 write10(int fd, uint32_t start_blk, uint16_t nblk, uchar_t *buf,
302 uint32_t bufsize)
303 {
304 struct uscsi_cmd *scmd;
305
306 scmd = get_uscsi_cmd();
307 scmd->uscsi_flags = USCSI_WRITE|USCSI_SILENT;
308 /*
309 * Some DVD drives take longer to write than
310 * the standard time, since they tend to generate
311 * the media TOC on the fly when the cache is full
312 */
313 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT * 3;
314 scmd->uscsi_cdb[0] = WRITE_10_CMD;
315 load_scsi32(&scmd->uscsi_cdb[2], start_blk);
316 scmd->uscsi_cdb[8] = nblk & 0xff;
317 scmd->uscsi_cdb[7] = (nblk >> 8) & 0xff;
318 scmd->uscsi_cdblen = 10;
319 scmd->uscsi_bufaddr = (char *)buf;
320 scmd->uscsi_buflen = bufsize;
321 if ((uscsi_error = uscsi(fd, scmd)) < 0)
322 return (0);
323 return (1);
324 }
325
326 int
close_track(int fd,int trackno,int close_session,int immediate)327 close_track(int fd, int trackno, int close_session, int immediate)
328 {
329 struct uscsi_cmd *scmd;
330
331 scmd = get_uscsi_cmd();
332 scmd->uscsi_flags = USCSI_SILENT;
333 scmd->uscsi_cdb[0] = CLOSE_TRACK_CMD;
334 if (immediate) {
335 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
336 scmd->uscsi_cdb[1] = 1;
337 } else {
338 scmd->uscsi_timeout = 240;
339 }
340 if ((close_session) || (device_type == DVD_PLUS) ||
341 (device_type == DVD_PLUS_W)) {
342 /* close the session */
343 scmd->uscsi_cdb[2] = 2;
344
345 } else {
346 /* Close the track but leave session open */
347 scmd->uscsi_cdb[2] = 1;
348 scmd->uscsi_cdb[5] = trackno & 0xff;
349 }
350
351 /*
352 * DVD+R media are already formatted, we are using
353 * a special case to notify that drive to close
354 * track/session and null-fill the remaining space.
355 */
356 if (device_type == DVD_PLUS) {
357 scmd->uscsi_cdb[5] = 1; /* only 1 track */
358
359 if (close_session) {
360 scmd->uscsi_cdb[2] = 6; /* session */
361 } else {
362 scmd->uscsi_cdb[2] = 1; /* track */
363 }
364 }
365
366 scmd->uscsi_cdblen = 10;
367 if ((uscsi_error = uscsi(fd, scmd)) < 0)
368 return (0);
369 return (1);
370 }
371
372 int
blank_disc(int fd,int type,int immediate)373 blank_disc(int fd, int type, int immediate)
374 {
375 struct uscsi_cmd *scmd;
376
377 scmd = get_uscsi_cmd();
378 scmd->uscsi_flags = USCSI_SILENT;
379
380 if (immediate) {
381 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
382 scmd->uscsi_cdb[1] = 0x10;
383 } else {
384 scmd->uscsi_timeout = 0x12c0;
385 }
386 ((uchar_t *)scmd->uscsi_cdb)[0] = BLANK_CMD;
387
388 /* tell it to blank the last session or all of the disk */
389 scmd->uscsi_cdb[1] |= type & 0x07;
390 scmd->uscsi_cdblen = 12;
391
392 if ((uscsi_error = uscsi(fd, scmd)) < 0)
393 return (0);
394 return (1);
395 }
396
397 int
read_cd(int fd,uint32_t start_blk,uint16_t nblk,uchar_t sector_type,uchar_t * buf,uint32_t bufsize)398 read_cd(int fd, uint32_t start_blk, uint16_t nblk, uchar_t sector_type,
399 uchar_t *buf, uint32_t bufsize)
400 {
401 struct uscsi_cmd *scmd;
402
403 scmd = get_uscsi_cmd();
404 scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
405 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
406 ((uchar_t *)scmd->uscsi_cdb)[0] = READ_CD_CMD;
407 scmd->uscsi_cdb[1] = (sector_type & 0x7) << 2;
408 scmd->uscsi_cdb[5] = start_blk & 0xff;
409 scmd->uscsi_cdb[4] = (start_blk >> 8) & 0xff;
410 scmd->uscsi_cdb[3] = (start_blk >> 16) & 0xff;
411 scmd->uscsi_cdb[2] = (start_blk >> 24) & 0xff;
412 scmd->uscsi_cdb[8] = nblk & 0xff;
413 scmd->uscsi_cdb[7] = (nblk >> 8) & 0xff;
414 scmd->uscsi_cdb[9] = 0x10;
415 scmd->uscsi_cdblen = 12;
416 scmd->uscsi_bufaddr = (char *)buf;
417 scmd->uscsi_buflen = bufsize;
418 if ((uscsi_error = uscsi(fd, scmd)) < 0)
419 return (0);
420 return (1);
421 }
422
423 int
load_unload(int fd,int load)424 load_unload(int fd, int load)
425 {
426 struct uscsi_cmd *scmd;
427
428 scmd = get_uscsi_cmd();
429 scmd->uscsi_flags = USCSI_SILENT;
430 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
431 scmd->uscsi_cdb[0] = START_STOP_CMD;
432 if (load == 0) {
433 /* unload medium */
434 scmd->uscsi_cdb[4] = 2;
435 } else {
436 /* load medium */
437 scmd->uscsi_cdb[4] = 3;
438 }
439 scmd->uscsi_cdblen = 6;
440
441 if ((uscsi_error = uscsi(fd, scmd)) < 0)
442 return (0);
443 return (1);
444 }
445
446 int
prevent_allow_mr(int fd,int op)447 prevent_allow_mr(int fd, int op)
448 {
449 struct uscsi_cmd *scmd;
450
451 scmd = get_uscsi_cmd();
452 scmd->uscsi_flags = USCSI_SILENT;
453 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
454 scmd->uscsi_cdb[0] = PREVENT_ALLOW_CMD;
455 if (!op) { /* prevent */
456 scmd->uscsi_cdb[4] = 1;
457 }
458 scmd->uscsi_cdblen = 6;
459 if ((uscsi_error = uscsi(fd, scmd)) < 0)
460 return (0);
461 return (1);
462 }
463
464 int
set_cd_speed(int fd,uint16_t read_speed,uint16_t write_speed)465 set_cd_speed(int fd, uint16_t read_speed, uint16_t write_speed)
466 {
467 struct uscsi_cmd *scmd;
468
469 scmd = get_uscsi_cmd();
470 scmd->uscsi_flags = USCSI_SILENT;
471 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
472 scmd->uscsi_cdblen = 0xc;
473 ((uchar_t *)scmd->uscsi_cdb)[0] = SET_CD_SPEED;
474 scmd->uscsi_cdb[2] = (read_speed >> 8) & 0xff;
475 scmd->uscsi_cdb[3] = read_speed & 0xff;
476 scmd->uscsi_cdb[4] = (write_speed >> 8) & 0xff;
477 scmd->uscsi_cdb[5] = write_speed & 0xff;
478
479 if ((uscsi_error = uscsi(fd, scmd)) < 0)
480 return (0);
481 return (1);
482 }
483
484 int
get_performance(int fd,int get_write_performance,uchar_t * perf)485 get_performance(int fd, int get_write_performance, uchar_t *perf)
486 {
487 struct uscsi_cmd *scmd;
488
489 scmd = get_uscsi_cmd();
490 scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
491 scmd->uscsi_buflen = GET_PERF_DATA_LEN;
492 scmd->uscsi_bufaddr = (char *)perf;
493 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
494 scmd->uscsi_cdblen = 0xc;
495 ((uchar_t *)scmd->uscsi_cdb)[0] = GET_PERFORMANCE_CMD;
496 scmd->uscsi_cdb[1] = 0x10;
497 if (get_write_performance)
498 scmd->uscsi_cdb[1] |= 4;
499 scmd->uscsi_cdb[9] = 2;
500 if ((uscsi_error = uscsi(fd, scmd)) < 0)
501 return (0);
502 return (1);
503 }
504
505 int
set_streaming(int fd,uchar_t * buf)506 set_streaming(int fd, uchar_t *buf)
507 {
508 struct uscsi_cmd *scmd;
509
510 scmd = get_uscsi_cmd();
511 scmd->uscsi_flags = USCSI_WRITE|USCSI_SILENT;
512 scmd->uscsi_buflen = SET_STREAM_DATA_LEN;
513 scmd->uscsi_bufaddr = (char *)buf;
514 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
515 scmd->uscsi_cdblen = 0xc;
516 ((uchar_t *)scmd->uscsi_cdb)[0] = STREAM_CMD;
517 scmd->uscsi_cdb[10] = SET_STREAM_DATA_LEN;
518 if ((uscsi_error = uscsi(fd, scmd)) < 0)
519 return (0);
520 return (1);
521 }
522
523 int
rezero_unit(int fd)524 rezero_unit(int fd)
525 {
526 struct uscsi_cmd *scmd;
527
528 scmd = get_uscsi_cmd();
529 scmd->uscsi_flags = USCSI_SILENT;
530 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
531 scmd->uscsi_cdblen = 0x6;
532 scmd->uscsi_cdb[0] = REZERO_UNIT_CMD;
533 if ((uscsi_error = uscsi(fd, scmd)) < 0)
534 return (0);
535 return (1);
536 }
537
538 int
start_stop(int fd,int start)539 start_stop(int fd, int start)
540 {
541 struct uscsi_cmd *scmd;
542
543 scmd = get_uscsi_cmd();
544 scmd->uscsi_flags = USCSI_SILENT;
545 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
546 scmd->uscsi_cdblen = 0x6;
547 scmd->uscsi_cdb[0] = START_STOP_CMD;
548 if (start) {
549 scmd->uscsi_cdb[4] = 1;
550 }
551 if ((uscsi_error = uscsi(fd, scmd)) < 0)
552 return (0);
553 return (1);
554 }
555
556 int
flush_cache(int fd)557 flush_cache(int fd)
558 {
559 struct uscsi_cmd *scmd;
560
561 scmd = get_uscsi_cmd();
562 scmd->uscsi_flags = USCSI_SILENT;
563 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
564 scmd->uscsi_cdblen = 10;
565 scmd->uscsi_cdb[0] = SYNC_CACHE_CMD;
566 if (device_type != CD_RW) {
567 scmd->uscsi_cdb[1] = 0x2; /* Immediate */
568 }
569
570 if ((uscsi_error = uscsi(fd, scmd)) < 0)
571 return (0);
572 return (1);
573 }
574
575 /*
576 * used for DVD- to reserve the size we want to write.
577 * This is used by the drive to generate a TOC.
578 */
579 int
set_reservation(int fd,ulong_t size)580 set_reservation(int fd, ulong_t size)
581 {
582 struct uscsi_cmd *scmd;
583
584 scmd = get_uscsi_cmd();
585 scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
586 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
587 scmd->uscsi_cdb[0] = SET_RESERVATION_CMD;
588 scmd->uscsi_cdblen = 10;
589 scmd->uscsi_cdb[5] = (uchar_t)(size >> 24);
590 scmd->uscsi_cdb[6] = (uchar_t)(size >> 16);
591 scmd->uscsi_cdb[7] = (uchar_t)(size >> 8);
592 scmd->uscsi_cdb[8] = (uchar_t)size;
593 if ((uscsi_error = uscsi(fd, scmd)) < 0)
594 return (0);
595 return (1);
596 }
597
598 /*
599 * Used for DVD+RW media to prepare the disk to write.
600 * It will also be used for packet mode writing when
601 * it becomes supported.
602 */
603 int
format_media(int fd)604 format_media(int fd)
605 {
606 struct uscsi_cmd *scmd;
607 uchar_t buf[20];
608
609 (void) memset(buf, 0, 20);
610 scmd = get_uscsi_cmd();
611 scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
612 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
613
614 scmd->uscsi_cdblen = 12;
615 scmd->uscsi_cdb[0] = READ_FORMAT_CAP_CMD;
616 scmd->uscsi_cdb[8] = 0x14; /* buffer length */
617 scmd->uscsi_buflen = 20;
618 scmd->uscsi_bufaddr = (char *)buf;
619
620 if ((uscsi_error = uscsi(fd, scmd)) < 0)
621 return (0);
622
623 /* RE-use cap structure */
624
625 scmd->uscsi_flags = USCSI_WRITE|USCSI_SILENT;
626 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
627 scmd->uscsi_cdblen = 6;
628 scmd->uscsi_cdb[0] = FORMAT_UNIT_CMD;
629 /* full format */
630 scmd->uscsi_cdb[1] = 0x11;
631 scmd->uscsi_buflen = 12;
632 buf[1] = 0x82; /* immediate and FOV */
633 buf[3] = 8; /* descriptor length */
634 buf[8] = 0x98; /* type = 26 DVD+RW format */
635 buf[10] = 0;
636
637 if ((uscsi_error = uscsi(fd, scmd)) < 0)
638 return (0);
639 return (1);
640 }
641
642
643 /*
644 * Prefered method of reading the media size. This is
645 * the only supported method on several newer drives.
646 */
647 uint32_t
read_format_capacity(int fd,uint_t * bsize)648 read_format_capacity(int fd, uint_t *bsize)
649 {
650 struct uscsi_cmd *scmd;
651 uint32_t filesize;
652 char buf[20];
653
654 scmd = get_uscsi_cmd();
655 scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
656 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
657 scmd->uscsi_cdblen = 12;
658 scmd->uscsi_cdb[0] = READ_FORMAT_CAP_CMD;
659 scmd->uscsi_cdb[8] = 0x14;
660 scmd->uscsi_buflen = 20;
661 scmd->uscsi_bufaddr = buf;
662
663 if ((uscsi_error = uscsi(fd, scmd)) < 0)
664 return (0);
665
666 filesize = (uint32_t)(((uchar_t)buf[4] << 24) +
667 ((uchar_t)buf[5] << 16) + ((uchar_t)buf[6] << 8) + (uchar_t)buf[7]);
668
669 *bsize = (uint16_t)(((uchar_t)buf[10] << 8) + (uchar_t)buf[11]);
670
671 return (filesize);
672 }
673
674 /*
675 * Used to reset the device. Since, sd(4D) requires a
676 * command to be issued when resetting a device we will
677 * issue an innocuous command. The command chosen for this
678 * purpose is the TEST UNIT READY (TUR) command. We also do
679 * not care about the sucess of the TUR so we will not return
680 * a value.
681 */
682 void
reset_dev(int fd)683 reset_dev(int fd)
684 {
685 struct uscsi_cmd *scmd;
686
687 /*
688 * Since a TUR has SCSI operation code of 0, we
689 * can make use of the fact that get_uscsi_cmd()
690 * initializes a CDB to all zeros to generate
691 * the TUR command.
692 */
693 scmd = get_uscsi_cmd();
694
695 /* Tell sd(4D) to do a silent reset of the device. */
696 scmd->uscsi_flags = USCSI_SILENT | USCSI_RESET;
697
698 scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
699 scmd->uscsi_cdblen = 6;
700
701 /* Issue the TUR command. */
702 uscsi_error = uscsi(fd, scmd);
703 }
704
705
706 /*
707 * Function: ftr_supported
708 *
709 * Description: Check to see if a device supports a Feature
710 *
711 * Arguments: fd - file descriptor
712 * feature - the MMC Feature for which we'd like to know
713 * if there's support
714 *
715 * Return Code: 1 - Feature is supported
716 * 0 - Feature is not supported
717 *
718 */
719 int
ftr_supported(int fd,uint16_t feature)720 ftr_supported(int fd, uint16_t feature)
721 {
722 size_t response_len;
723 uchar_t *bufp;
724 int ret;
725
726 response_len = MMC_FTR_HDR_LEN + MMC_FTR_DSCRPTR_BASE_LEN;
727 bufp = (uchar_t *)my_zalloc(response_len);
728
729 /*
730 * If a Feature is supported, a device will return a Feature Descriptor
731 * for that Feature, and its Current Bit will be set.
732 */
733 if (get_configuration(fd, feature, response_len, bufp) == 1) {
734 /*
735 * To check that a Feature Descriptor was returned, we
736 * check to see if the Data Length field of the Feature
737 * Header holds a value greater than four. To check if
738 * the Current Bit is set, we check bit 1 of byte 10.
739 */
740 if (read_scsi32(bufp) > 4 && bufp[10] & 1)
741 ret = 1;
742 else
743 ret = 0;
744 } else {
745 /* get_configuration failed */
746 ret = 0;
747 }
748 free(bufp);
749 return (ret);
750 }
751
752 /*
753 * Function: print_profile_name
754 *
755 * Description: Prints a list of the Profiles the device supports
756 *
757 * Parameters: num - hexadecimal representation of Profile
758 * current - 1 if the Profile is Current, otherwise 0
759 * abbr - 1 if printing abbreviated name, otherwise 0
760 */
761 void
print_profile_name(uint16_t num,uchar_t current,uchar_t abbr)762 print_profile_name(uint16_t num, uchar_t current, uchar_t abbr)
763 {
764 if (abbr != 1)
765 (void) printf(" 0x%04x: ", num);
766
767 switch (num) {
768 case 0x0000:
769 (void) printf("No Current Profile");
770 break;
771 case 0x0001:
772 (void) printf("Non-Removable Disk");
773 break;
774 case 0x0002:
775 (void) printf("Removable Disk");
776 break;
777 case 0x0003:
778 (void) printf("Magneto-Optical Erasable");
779 break;
780 case 0x0004:
781 (void) printf("Optical Write Once");
782 break;
783 case 0x0005:
784 (void) printf("AS-MO");
785 break;
786 case 0x0008:
787 (void) printf("CD-ROM");
788 break;
789 case 0x0009:
790 (void) printf("CD-R");
791 break;
792 case 0x000A:
793 (void) printf("CD-RW");
794 break;
795 case 0x0010:
796 (void) printf("DVD-ROM");
797 break;
798 case 0x0011:
799 (void) printf("DVD-R");
800 if (abbr != 1)
801 (void) printf(" Sequential Recording");
802 break;
803 case 0x0012:
804 (void) printf("DVD-RAM");
805 break;
806 case 0x0013:
807 (void) printf("DVD-RW");
808 if (abbr != 1)
809 (void) printf(" Restricted Overwrite");
810 break;
811 case 0x0014:
812 (void) printf("DVD-RW");
813 if (abbr != 1)
814 (void) printf(" Sequential Recording");
815 break;
816 case 0x0015:
817 (void) printf("DVD-R");
818 if (abbr != 1)
819 (void) printf(" Dual Layer Sequential Recording");
820 else
821 (void) printf(" DL");
822 break;
823 case 0x0016:
824 (void) printf("DVD-R");
825 if (abbr != 1)
826 (void) printf(" Dual Layer Jump Recording");
827 else
828 (void) printf(" DL");
829 break;
830 case 0x0017:
831 (void) printf("DVD-RW");
832 if (abbr != 1)
833 (void) printf(" Dual Layer");
834 else
835 (void) printf(" DL");
836 break;
837 case 0x001A:
838 (void) printf("DVD+RW");
839 break;
840 case 0x001B:
841 (void) printf("DVD+R");
842 break;
843 case 0x0020:
844 (void) printf("DDCD-ROM");
845 break;
846 case 0x0021:
847 (void) printf("DDCD-R");
848 break;
849 case 0x0022:
850 (void) printf("DDCD-RW");
851 break;
852 case 0x002A:
853 (void) printf("DVD+RW");
854 if (abbr != 1)
855 (void) printf(" Dual Layer");
856 else
857 (void) printf(" DL");
858 break;
859 case 0x002B:
860 (void) printf("DVD+R");
861 if (abbr != 1)
862 (void) printf(" Dual Layer");
863 else
864 (void) printf(" DL");
865 break;
866 case 0x0040:
867 (void) printf("BD-ROM");
868 break;
869 case 0x0041:
870 (void) printf("BD-R Sequential Recording (SRM) Profile");
871 break;
872 case 0x0042:
873 (void) printf("BD-R Random Recording (RRM) Profile");
874 break;
875 case 0x0043:
876 (void) printf("BD-RE");
877 break;
878 case 0xFFFF:
879 (void) printf("Nonstandard Profile");
880 break;
881 default:
882 break;
883 }
884 if (current == 1)
885 (void) printf(" (Current Profile)");
886 (void) printf("\n");
887 }
888
889 /*
890 * Function: print_profile_list
891 *
892 * Description: Print a list of Profiles supported by the Logical Unit.
893 *
894 * Parameters: fd - file descriptor for device whose list of
895 * profiles we wish to print
896 */
897 void
print_profile_list(int fd)898 print_profile_list(int fd)
899 {
900 size_t i;
901 size_t buflen;
902 uint16_t current;
903 uint16_t other;
904 uchar_t *bufp = (uchar_t *)my_zalloc(MMC_FTR_HDR_LEN);
905
906 /*
907 * First get_configuration call is used to determine amount of memory
908 * needed to hold all the Profiles. The first four bytes of bufp
909 * concatenated tell us the number of bytes of memory we need but do
910 * not take themselves into account. Therefore, add four, and
911 * allocate that number of bytes.
912 */
913 if (get_configuration(fd, MMC_FTR_PRFL_LIST, MMC_FTR_HDR_LEN,
914 bufp)) {
915 buflen = read_scsi32(bufp) + 4;
916 free(bufp);
917 bufp = (uchar_t *)my_zalloc(buflen);
918
919 /*
920 * Now get all the Profiles
921 */
922 if (get_configuration(fd, MMC_FTR_PRFL_LIST, buflen, bufp)) {
923 (void) printf("\nProfile List\n");
924 (void) printf("---------------------------------\n");
925
926 /*
927 * Find out the Logical Unit's Current Profile
928 */
929 current = read_scsi16(&bufp[6]);
930
931 /*
932 * Print out the Profile List and indicate which
933 * Profile is Current
934 */
935 for (i = MMC_FTR_HDR_LEN + MMC_FTR_DSCRPTR_BASE_LEN;
936 i < buflen; i += MMC_PRFL_DSCRPTR_LEN) {
937 other = read_scsi16(&bufp[i]);
938 if (other == current)
939 print_profile_name(other, 1, 0);
940 else
941 print_profile_name(other, 0, 0);
942 }
943 (void) printf("\n");
944 }
945 }
946 free(bufp);
947 }
948