comparison usr/src/cmd/iscsi/iscsitgtd/t10_ssc.c @ 0:c9caec207d52 b86

Initial porting based on b86
author Koji Uno <koji.uno@sun.com>
date Tue, 02 Jun 2009 18:56:50 +0900
parents
children 1a15d5aaf794
comparison
equal deleted inserted replaced
-1:000000000000 0:c9caec207d52
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 /*
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "@(#)t10_ssc.c 1.6 06/12/16 SMI"
28
29 /*
30 * Implementation of SSC-2 emulation
31 */
32
33 #include <strings.h>
34 #include <unistd.h>
35 #include <sys/types.h>
36 #include <aio.h>
37 #include <sys/asynch.h>
38 #include <sys/scsi/generic/sense.h>
39 #include <sys/scsi/generic/status.h>
40 #include <sys/scsi/targets/stdef.h>
41 #include <netinet/in.h>
42
43 #include "target.h"
44 #include "utility.h"
45 #include "t10.h"
46 #include "t10_spc.h"
47 #include "t10_ssc.h"
48
49 /*
50 * []----
51 * | Forward declarations
52 * []----
53 */
54 static scsi_cmd_table_t ssc_table[];
55 static void ssc_cmd(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len);
56 static void ssc_data(t10_cmd_t *cmd, emul_handle_t id, size_t offset,
57 char *data, size_t data_len);
58 static void ssc_free(emul_handle_t e);
59 static void ssc_write_cmplt(emul_handle_t e);
60 static void ssc_read_cmplt(emul_handle_t id);
61 static void ssc_setup_tape(ssc_params_t *s, t10_lu_common_t *lu);
62 static uint32_t find_last_obj_id(char *file_mark, off_t eod);
63 static char *sense_dev_config(ssc_params_t *s, char *data);
64 static char *sense_compression(ssc_params_t *s, char *data);
65
66 static long ssc_page_size;
67
68 /*
69 * []----
70 * | ssc_init_common -- initialize common information that all ITLs will use
71 * []----
72 */
73 Boolean_t
74 ssc_common_init(t10_lu_common_t *lu)
75 {
76 ssc_params_t *s;
77 ssc_obj_mark_t mark;
78
79 ssc_page_size = sysconf(_SC_PAGESIZE);
80
81 if (lu->l_mmap == MAP_FAILED)
82 return (False);
83
84 if ((s = (ssc_params_t *)calloc(1, sizeof (*s))) == NULL)
85 return (False);
86
87 s->s_size = lu->l_size;
88 s->s_fast_write_ack = lu->l_fast_write_ack;
89
90 bcopy(lu->l_mmap, &mark, sizeof (mark));
91 if (mark.som_sig != SSC_OBJ_SIG) {
92 ssc_setup_tape(s, lu);
93 }
94 s->s_cur_fm = 0;
95 s->s_cur_rec = sizeof (ssc_obj_mark_t);
96 s->s_prev_rec = s->s_cur_rec;
97 s->s_state = lu->l_state;
98
99 lu->l_dtype_params = (void *)s;
100 return (True);
101 }
102
103 /*
104 * []----
105 * | ssc_fini_common -- free any resources
106 * []----
107 */
108 void
109 ssc_common_fini(t10_lu_common_t *lu)
110 {
111 free(lu->l_dtype_params);
112 }
113
114 void
115 ssc_task_mgmt(t10_lu_common_t *lu, TaskOp_t op)
116 {
117 ssc_params_t *s = (ssc_params_t *)lu->l_dtype_params;
118
119 switch (op) {
120 case CapacityChange:
121 s->s_size = lu->l_size;
122 break;
123
124 case DeviceOnline:
125 s->s_state = lu->l_state;
126 }
127 }
128
129 /*
130 * []----
131 * | ssc_init_per -- initialize per ITL information
132 * []----
133 */
134 void
135 ssc_per_init(t10_lu_impl_t *itl)
136 {
137 ssc_params_t *s = (ssc_params_t *)itl->l_common->l_dtype_params;
138
139 if (s->s_state == lu_online)
140 itl->l_cmd = ssc_cmd;
141 else
142 itl->l_cmd = spc_cmd_offline;
143 itl->l_data = ssc_data;
144 itl->l_cmd_table = ssc_table;
145 }
146
147 /*
148 * []----
149 * | ssc_fini_per -- release or free any ITL resources
150 * []----
151 */
152 /*ARGSUSED*/
153 void
154 ssc_per_fini(t10_lu_impl_t *itl)
155 {
156 }
157
158 /*
159 * []----
160 * | ssc_cmd -- start a SCSI command
161 * |
162 * | This routine is called from within the SAM-3 Task router.
163 * []----
164 */
165 static void
166 ssc_cmd(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
167 {
168 scsi_cmd_table_t *e;
169
170 e = &cmd->c_lu->l_cmd_table[cdb[0]];
171 #ifdef FULL_DEBUG
172 queue_prt(mgmtq, Q_STE_IO, "SSC%x LUN%d Cmd %s\n",
173 cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num,
174 e->cmd_name == NULL ? "(no name)" : e->cmd_name);
175 #endif
176 (*e->cmd_start)(cmd, cdb, cdb_len);
177 }
178
179 /*
180 * []----
181 * | ssc_data -- Data phase for command.
182 * |
183 * | Normally this is only called for the WRITE command. Other commands
184 * | that have a data in phase will probably be short circuited when
185 * | we call trans_rqst_dataout() and the data is already available.
186 * | At least this is true for iSCSI. FC however will need a DataIn phase
187 * | for commands like MODE SELECT and PGROUT.
188 * []----
189 */
190 static void
191 ssc_data(t10_cmd_t *cmd, emul_handle_t id, size_t offset, char *data,
192 size_t data_len)
193 {
194 scsi_cmd_table_t *e;
195
196 e = &cmd->c_lu->l_cmd_table[cmd->c_cdb[0]];
197 #ifdef FULL_DEBUG
198 queue_prt(mgmtq, Q_STE_IO, "SSC%x LUN%d Data %s\n",
199 cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num,
200 e->cmd_name);
201 #endif
202 (*e->cmd_data)(cmd, id, offset, data, data_len);
203 }
204
205 /*
206 * []------------------------------------------------------------------[]
207 * | SCSI Streaming Commands - 3 |
208 * | T10/1611-D Revision 01c |
209 * | The following functions implement the emulation of SSC-3 type |
210 * | commands. |
211 * []------------------------------------------------------------------[]
212 */
213
214 /*ARGSUSED*/
215 static void
216 ssc_read(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
217 {
218 ssc_io_t *io;
219 ssc_params_t *s = (ssc_params_t *)T10_PARAMS_AREA(cmd);
220 ssc_obj_mark_t fm,
221 rm;
222 int fixed,
223 sili;
224 off_t offset = 0;
225 size_t xfer,
226 req_len;
227 void *mmap = cmd->c_lu->l_common->l_mmap;
228 t10_cmd_t *c;
229
230 fixed = cdb[1] & 0x01;
231 sili = cdb[1] & 0x02;
232
233 if (s == NULL)
234 return;
235
236 /*
237 * Standard error checking.
238 */
239 if ((sili && fixed) || (cdb[1] & 0xfc) ||
240 SAM_CONTROL_BYTE_RESERVED(cdb[5])) {
241 spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
242 spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00);
243 trans_send_complete(cmd, STATUS_CHECK);
244 return;
245 }
246
247 req_len = (cdb[2] << 16) | (cdb[3] << 8) | cdb[4];
248 req_len *= fixed ? 512 : 1;
249
250 if (req_len == 0) {
251 trans_send_complete(cmd, STATUS_GOOD);
252 return;
253 }
254
255 #ifdef FULL_DEBUG
256 queue_prt(mgmtq, Q_STE_IO,
257 "SSC%x LUN%d read 0x%x bytes",
258 cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, req_len);
259 #endif
260
261 bcopy((char *)mmap + s->s_cur_fm, &fm, sizeof (fm));
262 bcopy((char *)mmap + s->s_cur_fm + s->s_cur_rec, &rm, sizeof (rm));
263
264 if (rm.som_sig != SSC_OBJ_SIG) {
265 queue_prt(mgmtq, Q_STE_ERRS,
266 "SSC%x LUN%d bad RECORD-MARK",
267 cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num);
268 spc_sense_create(cmd, KEY_MEDIUM_ERROR, 0);
269 trans_send_complete(cmd, STATUS_CHECK);
270 return;
271 } else if (rm.som_type != SSC_OBJ_TYPE_RM) {
272 s->s_cur_fm += fm.o_fm.size;
273 s->s_cur_rec = sizeof (ssc_obj_mark_t);
274 s->s_prev_rec = s->s_cur_rec;
275
276 spc_sense_create(cmd, KEY_NO_SENSE, 0);
277 spc_sense_ascq(cmd, SPC_ASC_FM_DETECTED, SPC_ASCQ_FM_DETECTED);
278 spc_sense_info(cmd, req_len);
279 spc_sense_flags(cmd, SPC_SENSE_FM);
280 trans_send_complete(cmd, STATUS_CHECK);
281 return;
282 } else if ((sili == 0) &&
283 ((rm.o_rm.size - sizeof (ssc_obj_mark_t)) != req_len)) {
284 queue_prt(mgmtq, Q_STE_ERRS,
285 "SSC%x LUN%d Wrong size read",
286 cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num);
287
288 s->s_prev_rec = s->s_cur_rec;
289 s->s_cur_rec += rm.o_rm.size;
290
291 spc_sense_create(cmd, KEY_NO_SENSE, 0);
292 spc_sense_flags(cmd, SPC_SENSE_ILI);
293 trans_send_complete(cmd, STATUS_CHECK);
294 return;
295 }
296
297 do {
298 xfer = MIN((req_len - offset), T10_MAX_OUT(cmd));
299 if ((offset + xfer) < req_len)
300 c = trans_cmd_dup(cmd);
301 else
302 c = cmd;
303 if ((io = (ssc_io_t *)calloc(1, sizeof (*io))) == NULL) {
304 trans_send_complete(c, STATUS_BUSY);
305 return;
306 }
307
308 io->sio_cmd = c;
309 io->sio_offset = offset;
310 io->sio_total = req_len;
311 io->sio_data_len = xfer;
312 io->sio_data = (char *)mmap + s->s_cur_fm +
313 s->s_cur_rec + sizeof (ssc_obj_mark_t) + offset;
314 io->sio_aio.a_aio.aio_return = xfer;
315
316 ssc_read_cmplt((emul_handle_t)io);
317 offset += xfer;
318 } while (offset < req_len);
319
320 s->s_prev_rec = s->s_cur_rec;
321 s->s_cur_rec += req_len + sizeof (ssc_obj_mark_t);
322 }
323
324 static void
325 ssc_read_cmplt(emul_handle_t id)
326 {
327 ssc_io_t *io = (ssc_io_t *)id;
328 t10_cmd_t *cmd = io->sio_cmd;
329
330 if (io->sio_aio.a_aio.aio_return != io->sio_data_len) {
331 spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0);
332 trans_send_complete(cmd, STATUS_CHECK);
333 return;
334 }
335
336 if ((io->sio_offset + io->sio_data_len) < io->sio_total) {
337 if (trans_send_datain(cmd, io->sio_data, io->sio_data_len,
338 io->sio_offset, ssc_free, False, io) == False) {
339 trans_send_complete(cmd, STATUS_BUSY);
340 }
341 } else {
342 if (trans_send_datain(cmd, io->sio_data, io->sio_data_len,
343 io->sio_offset, ssc_free, True, io) == False) {
344 trans_send_complete(cmd, STATUS_BUSY);
345 }
346 }
347 }
348
349 /*ARGSUSED*/
350 static void
351 ssc_write(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
352 {
353 ssc_obj_mark_t mark;
354 size_t request_len,
355 max_xfer;
356 int fixed,
357 prev_id;
358 ssc_io_t *io;
359 ssc_params_t *s = (ssc_params_t *)T10_PARAMS_AREA(cmd);
360
361 if (s == NULL)
362 return;
363
364 if ((cdb[1] & 0xfe) || SAM_CONTROL_BYTE_RESERVED(cdb[5])) {
365 spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
366 spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00);
367 trans_send_complete(cmd, STATUS_CHECK);
368 return;
369 }
370 fixed = cdb[1];
371 request_len = (cdb[2] << 16) | (cdb[3] << 8) | cdb[4];
372 request_len *= fixed ? 512 : 1;
373
374 #ifdef FULL_DEBUG
375 queue_prt(mgmtq, Q_STE_IO,
376 "SSC%x LUN%d write %d, fixed %d",
377 cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num,
378 request_len, fixed);
379 #endif
380 io = cmd->c_emul_id;
381 if (io == NULL) {
382 if ((io = calloc(1, sizeof (*io))) == NULL) {
383 trans_send_complete(cmd, STATUS_BUSY);
384 return;
385 }
386 io->sio_total = request_len;
387 io->sio_cmd = cmd;
388 io->sio_offset = 0;
389
390 /*
391 * Writing looses all information after the current
392 * file-mark. So, check to see if the current file-mark
393 * size doesn't reflect the end-of-media. If not, update
394 * it.
395 */
396 bcopy((char *)cmd->c_lu->l_common->l_mmap + s->s_cur_fm,
397 &mark, sizeof (mark));
398 if (mark.o_fm.size !=
399 (s->s_size - sizeof (ssc_obj_mark_t) - s->s_cur_fm)) {
400 mark.o_fm.size = s->s_size - sizeof (ssc_obj_mark_t) -
401 s->s_cur_fm;
402 bcopy(&mark, (char *)cmd->c_lu->l_common->l_mmap +
403 s->s_cur_fm, sizeof (mark));
404 }
405
406 /*
407 * End-of-Partition detection
408 */
409 if ((s->s_cur_rec + request_len) > (mark.o_fm.size)) {
410 spc_sense_create(cmd, KEY_VOLUME_OVERFLOW, 0);
411 spc_sense_ascq(cmd, SPC_ASC_EOP, SPC_ASCQ_EOP);
412 spc_sense_flags(cmd, SPC_SENSE_EOM);
413 trans_send_complete(cmd, STATUS_CHECK);
414 return;
415 }
416
417 if ((s->s_cur_fm == 0) &&
418 (s->s_cur_rec == sizeof (ssc_obj_mark_t))) {
419
420 /*
421 * The current position is a BOM. By setting
422 * the prev_id value to -1 the code below will
423 * create the first ID with a value of zero
424 * Which is what the specification requires.
425 */
426 prev_id = -1;
427
428 } else if (s->s_cur_rec == sizeof (ssc_obj_mark_t)) {
429
430 /*
431 * If the current position is at the beginning of
432 * this file-mark use the object ID found in
433 * the file-mark header. It will have been updated
434 * from the last object ID in the previous file-mark.
435 *
436 * NOTE: We're counting on 'mark' still referring
437 * to the current file mark here.
438 */
439 prev_id = mark.o_fm.last_obj_id;
440 } else {
441 bcopy((char *)cmd->c_lu->l_common->l_mmap +
442 s->s_cur_fm + s->s_prev_rec, &mark, sizeof (mark));
443 prev_id = mark.o_rm.obj_id;
444 }
445
446 bzero(&mark, sizeof (mark));
447 mark.som_sig = SSC_OBJ_SIG;
448 mark.som_type = SSC_OBJ_TYPE_RM;
449 mark.o_rm.size = request_len +
450 sizeof (ssc_obj_mark_t);
451 mark.o_rm.obj_id = prev_id + 1;
452 bcopy(&mark, (char *)cmd->c_lu->l_common->l_mmap +
453 s->s_cur_fm + s->s_cur_rec, sizeof (mark));
454 }
455
456 max_xfer = min(io->sio_total - io->sio_offset,
457 cmd->c_lu->l_targ->s_maxout);
458 io->sio_aio.a_aio.aio_return = max_xfer;
459 io->sio_data_len = max_xfer;
460 io->sio_data = (char *)cmd->c_lu->l_common->l_mmap +
461 s->s_cur_fm + s->s_cur_rec + sizeof (mark) + io->sio_offset;
462
463 if (trans_rqst_dataout(cmd, io->sio_data, io->sio_data_len,
464 io->sio_offset, io, ssc_free) == False) {
465 trans_send_complete(cmd, STATUS_BUSY);
466 }
467 }
468
469 /*ARGSUSED*/
470 static void
471 ssc_write_data(t10_cmd_t *cmd, emul_handle_t id, size_t offset, char *data,
472 size_t data_len)
473 {
474 ssc_io_t *io = (ssc_io_t *)id;
475 ssc_params_t *s = (ssc_params_t *)T10_PARAMS_AREA(cmd);
476
477 if (s == NULL)
478 return;
479
480 if (s->s_fast_write_ack == False) {
481 uint64_t sa;
482 size_t len;
483
484 /*
485 * msync requires the address to be page aligned.
486 * That means we need to account for any alignment
487 * loss in the len field and access the full page.
488 */
489 sa = (uint64_t)(intptr_t)data & ~(ssc_page_size - 1);
490 len = (((size_t)data & (ssc_page_size - 1)) +
491 data_len + ssc_page_size - 1) &
492 ~(ssc_page_size -1);
493
494 /*
495 * We only need to worry about sync'ing the blocks
496 * in the mmap case because if the fast cache isn't
497 * enabled for AIO the file will be opened with F_SYNC
498 * which performs the correct action.
499 */
500 if (msync((char *)(intptr_t)sa, len, MS_SYNC) == -1) {
501 perror("msync");
502 spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0);
503 trans_send_complete(cmd, STATUS_CHECK);
504 return;
505 }
506 }
507 ssc_write_cmplt((emul_handle_t)io);
508 }
509
510 static void
511 ssc_write_cmplt(emul_handle_t e)
512 {
513 ssc_io_t *io = (ssc_io_t *)e;
514 t10_cmd_t *cmd = io->sio_cmd;
515 ssc_params_t *s = (ssc_params_t *)T10_PARAMS_AREA(cmd);
516
517 if (s == NULL)
518 return;
519
520 if ((io->sio_offset + io->sio_data_len) < io->sio_total) {
521 io->sio_offset += io->sio_data_len;
522 ssc_write(cmd, cmd->c_cdb, cmd->c_cdb_len);
523 return;
524 }
525
526 s->s_prev_rec = s->s_cur_rec;
527 s->s_cur_rec += io->sio_total + sizeof (ssc_obj_mark_t);
528 free(io);
529 trans_send_complete(cmd, STATUS_GOOD);
530 }
531
532 /*ARGSUSED*/
533 static void
534 ssc_rewind(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
535 {
536 ssc_params_t *s = (ssc_params_t *)T10_PARAMS_AREA(cmd);
537
538 if (s == NULL)
539 return;
540
541 if ((cdb[1] & ~SSC_REWIND_IMMED) || cdb[2] || cdb[3] || cdb[4] ||
542 SAM_CONTROL_BYTE_RESERVED(cdb[5])) {
543 spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
544 spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00);
545 trans_send_complete(cmd, STATUS_CHECK);
546 return;
547 }
548
549 s->s_cur_fm = 0;
550 s->s_cur_rec = sizeof (ssc_obj_mark_t);
551 trans_send_complete(cmd, STATUS_GOOD);
552 }
553
554 /*ARGSUSED*/
555 static void
556 ssc_read_limits(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
557 {
558 struct read_blklim *rb;
559 int min_size = 512;
560
561 if (cdb[1] || cdb[2] || cdb[3] || cdb[4] ||
562 SAM_CONTROL_BYTE_RESERVED(cdb[5])) {
563 spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
564 spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00);
565 trans_send_complete(cmd, STATUS_CHECK);
566 return;
567 }
568
569 if ((rb = (struct read_blklim *)calloc(1, sizeof (*rb))) == NULL) {
570 trans_send_complete(cmd, STATUS_BUSY);
571 return;
572 }
573
574 /*
575 * maximum block size is set to zero to indicate no maximum block
576 * limit is specified.
577 */
578 rb->granularity = 9; /* 512 block sizes */
579 rb->min_hi = hibyte(min_size);
580 rb->min_lo = lobyte(min_size);
581
582 if (trans_send_datain(cmd, (char *)rb, sizeof (*rb), 0, ssc_free,
583 True, (emul_handle_t)rb) == False) {
584 trans_send_complete(cmd, STATUS_BUSY);
585 }
586 }
587
588 /*ARGSUSED*/
589 static void
590 ssc_space(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
591 {
592 int code,
593 count;
594 ssc_params_t *s = T10_PARAMS_AREA(cmd);
595 ssc_obj_mark_t mark;
596 t10_lu_common_t *lu = cmd->c_lu->l_common;
597
598 if (s == NULL)
599 return;
600
601 if ((cdb[1] & 0xf0) || SAM_CONTROL_BYTE_RESERVED(cdb[5])) {
602 spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
603 spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00);
604 trans_send_complete(cmd, STATUS_CHECK);
605 return;
606 }
607
608 code = cdb[1] & 0x0f;
609 count = (cdb[2] << 16) | (cdb[3] << 8) | cdb[4];
610
611 if ((count == 0) && (code != SSC_SPACE_CODE_END_OF_DATA)) {
612 trans_send_complete(cmd, STATUS_GOOD);
613 return;
614 }
615
616 switch (code) {
617 case SSC_SPACE_CODE_BLOCKS:
618 if (count < 0) {
619 bcopy((char *)lu->l_mmap + s->s_cur_fm + s->s_cur_rec,
620 &mark, sizeof (mark));
621 if ((mark.som_sig == SSC_OBJ_SIG) &&
622 (mark.som_type == SSC_OBJ_TYPE_RM)) {
623 count = mark.o_rm.obj_id + count;
624
625 /*
626 * If the count is still negative it means
627 * the request is still attempting to go
628 * beyond the beginning of the file mark.
629 */
630 if (count < 0) {
631 count *= -1;
632 spc_sense_create(cmd, KEY_NO_SENSE, 0);
633 spc_sense_ascq(cmd,
634 SPC_ASC_FM_DETECTED,
635 SPC_ASCQ_FM_DETECTED);
636 spc_sense_info(cmd, count);
637 trans_send_complete(cmd, STATUS_CHECK);
638 return;
639 }
640 s->s_cur_rec = s->s_cur_fm + sizeof (mark);
641 } else {
642 /*
643 * Something is not right. We'll let the
644 * processing below determine exactly what
645 * is wrong. So don't update the record
646 * mark and sent the count to 1.
647 */
648 count = 1;
649 }
650 }
651
652 while (count) {
653 bcopy((char *)lu->l_mmap + s->s_cur_fm + s->s_cur_rec,
654 &mark, sizeof (mark));
655
656 /*
657 * Something internally bad has happened with
658 * the marks in the file.
659 */
660 if (mark.som_sig != SSC_OBJ_SIG) {
661 queue_prt(mgmtq, Q_STE_ERRS,
662 "SSC%x LUN%d, bad sig mark: "
663 "expected=0x%x, got=0x%x",
664 cmd->c_lu->l_targ->s_targ_num,
665 cmd->c_lu->l_common->l_num,
666 SSC_OBJ_SIG, mark.som_sig);
667 spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0);
668 trans_send_complete(cmd, STATUS_CHECK);
669 return;
670 }
671
672 /*
673 * Hit a filemark. Update the current record if
674 * we're not at the End-Of-Medium.
675 */
676 if (mark.som_type == SSC_OBJ_TYPE_FM) {
677 if (mark.o_fm.eom == True) {
678 spc_sense_create(cmd, KEY_MEDIUM_ERROR,
679 0);
680 spc_sense_ascq(cmd, SPC_ASC_EOP,
681 SPC_ASCQ_EOP);
682 spc_sense_info(cmd, count);
683 spc_sense_flags(cmd, SPC_SENSE_EOM);
684 trans_send_complete(cmd, STATUS_CHECK);
685 return;
686 }
687 s->s_cur_fm += s->s_cur_rec;
688 s->s_cur_rec += sizeof (mark);
689 spc_sense_create(cmd, KEY_NO_SENSE, 0);
690 spc_sense_ascq(cmd, SPC_ASC_FM_DETECTED,
691 SPC_ASCQ_FM_DETECTED);
692 spc_sense_info(cmd, count);
693 trans_send_complete(cmd, STATUS_CHECK);
694 return;
695 }
696 s->s_cur_rec += mark.o_rm.size;
697 count--;
698 }
699 trans_send_complete(cmd, STATUS_CHECK);
700 break;
701
702 case SSC_SPACE_CODE_FILEMARKS:
703 if (count < 0) {
704 bcopy((char *)lu->l_mmap + s->s_cur_fm, &mark,
705 sizeof (mark));
706 if ((mark.som_sig == SSC_OBJ_SIG) &&
707 (mark.som_type == SSC_OBJ_TYPE_FM)) {
708 count = mark.o_fm.num + count;
709
710 /*
711 * If the count is still negative it means
712 * the request is still attempting to go
713 * beyond the beginning of the file mark.
714 */
715 if (count < 0) {
716 count *= -1;
717 spc_sense_create(cmd, KEY_NO_SENSE, 0);
718 spc_sense_ascq(cmd,
719 SPC_ASC_FM_DETECTED,
720 SPC_ASCQ_FM_DETECTED);
721 spc_sense_info(cmd, count);
722 trans_send_complete(cmd, STATUS_CHECK);
723 return;
724 }
725 s->s_cur_fm = 0;
726 s->s_cur_rec = sizeof (ssc_obj_mark_t);
727 } else {
728 /*
729 * Something is not right. We'll let the
730 * processing below determine exactly what
731 * is wrong. So don't update the record
732 * mark and sent the count to 1.
733 */
734 count = 1;
735 }
736 }
737
738 while (count--) {
739 bcopy((char *)lu->l_mmap + s->s_cur_fm, &mark,
740 sizeof (mark));
741 if (mark.som_sig != SSC_OBJ_SIG) {
742 queue_prt(mgmtq, Q_STE_ERRS,
743 "SSC%x LUN%d, bad sig mark: "
744 "expected=0x%x, got=0x%x",
745 cmd->c_lu->l_targ->s_targ_num,
746 cmd->c_lu->l_common->l_num,
747 SSC_OBJ_SIG, mark.som_sig);
748 spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0);
749 trans_send_complete(cmd, STATUS_CHECK);
750 return;
751 }
752 if (mark.som_type != SSC_OBJ_TYPE_FM) {
753 queue_prt(mgmtq, Q_STE_ERRS,
754 "SSC%x LUN%d, bad mark type: "
755 "expected=0x%x, got=0x%x",
756 cmd->c_lu->l_targ->s_targ_num,
757 cmd->c_lu->l_common->l_num,
758 SSC_OBJ_TYPE_FM, mark.som_type);
759 spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0);
760 trans_send_complete(cmd, STATUS_CHECK);
761 return;
762 }
763 if (mark.o_fm.eom == True) {
764 spc_sense_create(cmd, KEY_MEDIUM_ERROR, 0);
765 spc_sense_ascq(cmd, SPC_ASC_EOP, SPC_ASCQ_EOP);
766 spc_sense_info(cmd, count);
767 spc_sense_flags(cmd, SPC_SENSE_EOM);
768 trans_send_complete(cmd, STATUS_CHECK);
769 return;
770 }
771 s->s_cur_fm += mark.o_fm.size;
772 }
773 trans_send_complete(cmd, STATUS_GOOD);
774 break;
775
776 default:
777 spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
778 spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00);
779 trans_send_complete(cmd, STATUS_CHECK);
780 return;
781 }
782 }
783
784 /*
785 * []----
786 * | ssc_msense -- MODE SENSE command
787 * |
788 * | This command is part of the SPC set, but is device specific enough
789 * | that it must be emulated in each device type.
790 * []----
791 */
792 /*ARGSUSED*/
793 static void
794 ssc_msense(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
795 {
796 ssc_params_t *s = T10_PARAMS_AREA(cmd);
797 struct mode_header *mode_hdr;
798 int request_len,
799 alloc_len;
800 char *data,
801 *np;
802
803 /*
804 * SPC-3 Revision 21c section 6.8
805 * Reserve bit checks
806 */
807 if ((cdb[1] & ~8) || SAM_CONTROL_BYTE_RESERVED(cdb[5])) {
808 spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
809 spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00);
810 trans_send_complete(cmd, STATUS_CHECK);
811 return;
812 }
813
814 /*
815 * Zero length causes a simple ack to occur.
816 */
817 if (cdb[4] == 0) {
818 trans_send_complete(cmd, STATUS_GOOD);
819 return;
820 } else {
821 request_len = cdb[4];
822 alloc_len = max(request_len,
823 sizeof (*mode_hdr) + MODE_BLK_DESC_LENGTH +
824 sizeof (ssc_data_compression_t) + sizeof (*mode_hdr) +
825 MODE_BLK_DESC_LENGTH + sizeof (ssc_device_config_t));
826 }
827
828 queue_prt(mgmtq, Q_STE_NONIO, "SSC%x LUN%d: MODE_SENSE(0x%x)",
829 cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, cdb[2]);
830
831 if ((data = memalign(sizeof (void *), alloc_len)) == NULL) {
832 trans_send_complete(cmd, STATUS_BUSY);
833 return;
834 }
835
836 mode_hdr = (struct mode_header *)data;
837
838 switch (cdb[2]) {
839 case MODE_SENSE_COMPRESSION:
840 mode_hdr->length = sizeof (ssc_data_compression_t);
841 mode_hdr->bdesc_length = MODE_BLK_DESC_LENGTH;
842 (void) sense_compression(s, data + sizeof (*mode_hdr) +
843 mode_hdr->bdesc_length);
844 break;
845
846 case MODE_SENSE_DEV_CONFIG:
847 mode_hdr->length = sizeof (ssc_device_config_t);
848 mode_hdr->bdesc_length = MODE_BLK_DESC_LENGTH;
849 (void) sense_dev_config(s, data + sizeof (*mode_hdr) +
850 mode_hdr->bdesc_length);
851 break;
852
853 case MODE_SENSE_SEND_ALL:
854 np = sense_compression(s, data);
855 (void) sense_dev_config(s, np);
856 break;
857
858 case 0x00:
859 bzero(data, alloc_len);
860 break;
861
862 default:
863 queue_prt(mgmtq, Q_STE_ERRS,
864 "SSC%x LUN%d: MODE SENSE(0x%x) not handled",
865 cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num,
866 cdb[2]);
867 spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
868 spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00);
869 trans_send_complete(cmd, STATUS_CHECK);
870 return;
871 }
872
873 if (trans_send_datain(cmd, (char *)data, request_len, 0, ssc_free,
874 True, data) == False) {
875 trans_send_complete(cmd, STATUS_BUSY);
876 }
877 }
878
879 /*ARGSUSED*/
880 static void
881 ssc_read_pos(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
882 {
883 int service_action,
884 request_len,
885 alloc_len;
886 pos_short_form_t *sf;
887 void *data;
888 ssc_params_t *s = (ssc_params_t *)T10_PARAMS_AREA(cmd);
889 ssc_obj_mark_t mark;
890
891 if (s == NULL)
892 return;
893
894 /*
895 * Standard reserve bit check
896 */
897 if ((cdb[1] & 0xc0) || cdb[2] || cdb[3] || cdb[4] || cdb[5] ||
898 cdb[6] || SAM_CONTROL_BYTE_RESERVED(cdb[9])) {
899 spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
900 spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00);
901 trans_send_complete(cmd, STATUS_CHECK);
902 return;
903 }
904
905 service_action = cdb[1] & 0x1f;
906 request_len = (cdb[7] << 8) | cdb[8];
907 switch (service_action) {
908 case SSC_READ_POS_SHORT_FORM:
909 alloc_len = max(request_len, sizeof (*sf));
910 if ((data = memalign(sizeof (void *), alloc_len)) == NULL) {
911 trans_send_complete(cmd, STATUS_BUSY);
912 return;
913 }
914 sf = (pos_short_form_t *)data;
915 bcopy((char *)cmd->c_lu->l_common->l_mmap + s->s_cur_fm,
916 &mark, sizeof (mark));
917 if ((mark.o_fm.bom == True) &&
918 (s->s_cur_rec == sizeof (ssc_obj_mark_t)))
919 sf->bop = 1;
920 bcopy((char *)cmd->c_lu->l_common->l_mmap + s->s_cur_fm +
921 s->s_cur_rec, &mark, sizeof (mark));
922 sf->first_obj[0] = hibyte(hiword(mark.o_rm.obj_id));
923 sf->first_obj[1] = lobyte(hiword(mark.o_rm.obj_id));
924 sf->first_obj[2] = hibyte(loword(mark.o_rm.obj_id));
925 sf->first_obj[3] = lobyte(loword(mark.o_rm.obj_id));
926
927 /*
928 * We mark the last object to be the same as the first
929 * object which indicates that nothing is currently
930 * buffered.
931 */
932 sf->last_obj[0] = sf->first_obj[0];
933 sf->last_obj[1] = sf->first_obj[1];
934 sf->last_obj[2] = sf->first_obj[2];
935 sf->last_obj[3] = sf->first_obj[3];
936
937 break;
938
939 case SSC_READ_POS_LONG_FORM:
940 spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
941 spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00);
942 trans_send_complete(cmd, STATUS_CHECK);
943 return;
944
945 default:
946 spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
947 spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00);
948 trans_send_complete(cmd, STATUS_CHECK);
949 return;
950 }
951
952 if (trans_send_datain(cmd, (char *)data, request_len, 0, ssc_free,
953 True, data) == False) {
954 trans_send_complete(cmd, STATUS_BUSY);
955 }
956 }
957
958 /*ARGSUSED*/
959 static void
960 ssc_rpt_density(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
961 {
962 ssc_density_t *d;
963 ssc_density_media_t *dm;
964 ssc_params_t *s = (ssc_params_t *)T10_PARAMS_AREA(cmd);
965 size_t cap = s->s_size / (1024 * 1024);
966 int medium_type,
967 request_len,
968 alloc_len;
969 void *data;
970
971 if (s == NULL)
972 return;
973
974 if ((cdb[1] & 0xfc) || cdb[2] || cdb[3] || cdb[4] || cdb[5] ||
975 cdb[6] || SAM_CONTROL_BYTE_RESERVED(cdb[9])) {
976 spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
977 spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00);
978 trans_send_complete(cmd, STATUS_CHECK);
979 return;
980 }
981
982 medium_type = cdb[1] & 0x2;
983 request_len = (cdb[7] << 8) | cdb[8];
984 alloc_len = max(request_len, max(sizeof (*d), sizeof (*dm)));
985 if ((data = memalign(sizeof (void *), alloc_len)) == NULL) {
986 trans_send_complete(cmd, STATUS_BUSY);
987 return;
988 }
989 if (medium_type == 0) {
990 d = (ssc_density_t *)data;
991 d->d_hdr.len = htons(sizeof (*d) -
992 sizeof (ssc_density_header_t));
993 d->d_prim_code = 1;
994 d->d_wrtok = 1;
995 d->d_deflt = 1;
996 d->d_tracks[1] = 1;
997 d->d_capacity[0] = hibyte(hiword(cap));
998 d->d_capacity[1] = lobyte(hiword(cap));
999 d->d_capacity[2] = hibyte(loword(cap));
1000 d->d_capacity[3] = lobyte(loword(cap));
1001 bcopy(cmd->c_lu->l_common->l_vid, d->d_organization,
1002 min(sizeof (d->d_organization),
1003 strlen(cmd->c_lu->l_common->l_vid)));
1004 bcopy(cmd->c_lu->l_common->l_pid, d->d_description,
1005 min(sizeof (d->d_description),
1006 strlen(cmd->c_lu->l_common->l_pid)));
1007 } else {
1008 dm = (ssc_density_media_t *)data;
1009 dm->d_hdr.len = htons(sizeof (*d) -
1010 sizeof (ssc_density_header_t));
1011 bcopy(cmd->c_lu->l_common->l_vid, d->d_organization,
1012 min(sizeof (d->d_organization),
1013 strlen(cmd->c_lu->l_common->l_vid)));
1014 bcopy(cmd->c_lu->l_common->l_pid, dm->d_description,
1015 min(sizeof (dm->d_description),
1016 strlen(cmd->c_lu->l_common->l_pid)));
1017 }
1018
1019 if (trans_send_datain(cmd, (char *)data, request_len, 0, ssc_free,
1020 True, (emul_handle_t)data) == False) {
1021 trans_send_complete(cmd, STATUS_BUSY);
1022 }
1023 }
1024
1025 /*ARGSUSED*/
1026 static void
1027 ssc_write_fm(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
1028 {
1029 int marks_requested;
1030 off_t next_size;
1031 ssc_params_t *s = (ssc_params_t *)T10_PARAMS_AREA(cmd);
1032 ssc_obj_mark_t mark_fm;
1033
1034 if (s == NULL)
1035 return;
1036
1037 if ((cdb[1] & 0xfc) || SAM_CONTROL_BYTE_RESERVED(cdb[5])) {
1038 spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
1039 spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00);
1040 trans_send_complete(cmd, STATUS_CHECK);
1041 return;
1042 }
1043
1044 marks_requested = (cdb[2] << 16) | (cdb[3] << 8) | cdb[4];
1045 while (marks_requested--) {
1046 /*
1047 * Get the last file-mark and update it's size.
1048 */
1049 bcopy((char *)cmd->c_lu->l_common->l_mmap + s->s_cur_fm,
1050 &mark_fm, sizeof (mark_fm));
1051 if (mark_fm.som_sig != SSC_OBJ_SIG) {
1052 spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0);
1053 trans_send_complete(cmd, STATUS_CHECK);
1054 return;
1055 }
1056 next_size = mark_fm.o_fm.size - s->s_cur_rec;
1057 mark_fm.o_fm.size = s->s_cur_rec;
1058 bcopy(&mark_fm, (char *)cmd->c_lu->l_common->l_mmap +
1059 s->s_cur_fm, sizeof (mark_fm));
1060
1061 /*
1062 * Write new mark and update internal location of mark.
1063 */
1064 mark_fm.o_fm.last_obj_id =
1065 find_last_obj_id((char *)cmd->c_lu->l_common->l_mmap +
1066 s->s_cur_fm, s->s_cur_rec);
1067 mark_fm.o_fm.bom = False;
1068 mark_fm.o_fm.size = next_size;
1069 s->s_cur_fm += s->s_cur_rec;
1070 s->s_cur_rec = sizeof (ssc_obj_mark_t);
1071 s->s_prev_rec = s->s_cur_rec;
1072 bcopy(&mark_fm, (char *)cmd->c_lu->l_common->l_mmap +
1073 s->s_cur_fm, sizeof (mark_fm));
1074 mark_fm.o_fm.size = 0;
1075 bcopy(&mark_fm, (char *)cmd->c_lu->l_common->l_mmap +
1076 s->s_cur_fm + s->s_cur_rec, sizeof (mark_fm));
1077 }
1078 trans_send_complete(cmd, STATUS_GOOD);
1079 }
1080
1081 /*ARGSUSED*/
1082 static void
1083 ssc_locate(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
1084 {
1085 }
1086
1087 /*ARGSUSED*/
1088 static void
1089 ssc_erase(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
1090 {
1091 ssc_obj_mark_t mark;
1092 ssc_params_t *s = (ssc_params_t *)T10_PARAMS_AREA(cmd);
1093
1094 if (s == NULL)
1095 return;
1096
1097 bzero(&mark, sizeof (mark));
1098 mark.som_sig = SSC_OBJ_SIG;
1099 mark.som_type = SSC_OBJ_TYPE_FM;
1100 mark.o_fm.bom = True;
1101 mark.o_fm.eom = False;
1102 mark.o_fm.size = s->s_size - sizeof (mark);
1103
1104 bcopy(&mark, (char *)cmd->c_lu->l_common->l_mmap, sizeof (mark));
1105 }
1106
1107 /*ARGSUSED*/
1108 static void
1109 ssc_load(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
1110 {
1111 ssc_params_t *s = T10_PARAMS_AREA(cmd);
1112 t10_lu_common_t *lu = cmd->c_lu->l_common;
1113 ssc_obj_mark_t mark;
1114
1115 /*
1116 * SSC-3, revision 02, section 7.2 LOAD/UNLOAD command
1117 * Check for various reserve bits.
1118 */
1119 if ((cdb[1] & ~SSC_LOAD_CMD_IMMED) || cdb[2] || cdb[3] ||
1120 (cdb[4] & ~(SSC_LOAD_CMD_LOAD | SSC_LOAD_CMD_RETEN |
1121 SSC_LOAD_CMD_EOT | SSC_LOAD_CMD_HOLD)) ||
1122 SAM_CONTROL_BYTE_RESERVED(cdb[5])) {
1123 spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
1124 spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0);
1125 trans_send_complete(cmd, STATUS_CHECK);
1126 return;
1127 }
1128
1129 queue_prt(mgmtq, Q_STE_NONIO, "SSC%x LUN%d load bits 0x%x",
1130 cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, cdb[4]);
1131
1132 /*
1133 * There are four possible actions based on the LOAD and HOLD
1134 * bits.
1135 */
1136 switch (cdb[4] & (SSC_LOAD_CMD_LOAD|SSC_LOAD_CMD_HOLD)) {
1137 case SSC_LOAD_CMD_LOAD|SSC_LOAD_CMD_HOLD:
1138 /*
1139 * Load the media into the system if not already done
1140 * so, but do not position tape. The EOT and RETEN should
1141 * be zero. Since this emulation currently is always available
1142 * we're good to go.
1143 */
1144 break;
1145
1146 case SSC_LOAD_CMD_LOAD:
1147 /*
1148 * Without the HOLD bit the tape should be positioned at
1149 * the beginning of partition 0.
1150 */
1151 s->s_cur_fm = 0;
1152 s->s_cur_rec = sizeof (ssc_obj_mark_t);
1153 break;
1154
1155 case SSC_LOAD_CMD_HOLD:
1156 /*
1157 * Without the LOAD bit we leave the tape online, but look
1158 * at the RETEN and EOT bits. The RETEN doesn't mean anything
1159 * for this virtual tape, but we can reposition to EOT.
1160 */
1161 if (cdb[4] & SSC_LOAD_CMD_EOT) {
1162 /*CONSTANTCONDITION*/
1163 while (1) {
1164 bcopy((char *)lu->l_mmap + s->s_cur_fm, &mark,
1165 sizeof (mark));
1166 if (mark.som_sig != SSC_OBJ_SIG) {
1167 queue_prt(mgmtq, Q_STE_ERRS,
1168 "SSC%x LUN%d, bad sig mark: "
1169 "expected=0x%x, got=0x%x",
1170 cmd->c_lu->l_targ->s_targ_num,
1171 cmd->c_lu->l_common->l_num,
1172 SSC_OBJ_SIG, mark.som_sig);
1173 spc_sense_create(cmd,
1174 KEY_MEDIUM_ERROR, 0);
1175 trans_send_complete(cmd, STATUS_CHECK);
1176 return;
1177 }
1178 if (mark.som_type != SSC_OBJ_TYPE_FM) {
1179 queue_prt(mgmtq, Q_STE_ERRS,
1180 "SSC%x LUN%d, bad mark type: "
1181 "expected=0x%x, got=0x%x",
1182 cmd->c_lu->l_targ->s_targ_num,
1183 cmd->c_lu->l_common->l_num,
1184 SSC_OBJ_TYPE_FM, mark.som_type);
1185 spc_sense_create(cmd,
1186 KEY_MEDIUM_ERROR, 0);
1187 trans_send_complete(cmd, STATUS_CHECK);
1188 return;
1189 }
1190 if (mark.o_fm.eom == True)
1191 break;
1192 s->s_cur_fm += mark.o_fm.size;
1193 }
1194 }
1195 break;
1196
1197 case 0:
1198 /*
1199 * Unload the current tape.
1200 */
1201
1202 break;
1203 }
1204 trans_send_complete(cmd, STATUS_GOOD);
1205 }
1206
1207 /*ARGSUSED*/
1208 static void
1209 ssc_logsense(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
1210 {
1211 spc_log_supported_pages_t p;
1212 void *v;
1213
1214 /*
1215 * Reserve bit checks
1216 */
1217 if ((cdb[1] & ~(SSC_LOG_SP|SSC_LOG_PPC)) || cdb[3] || cdb[4] ||
1218 SAM_CONTROL_BYTE_RESERVED(cdb[9])) {
1219 spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
1220 spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0);
1221 trans_send_complete(cmd, STATUS_CHECK);
1222 return;
1223 }
1224
1225 queue_prt(mgmtq, Q_STE_ERRS, "SSC%x LUN%d page code 0x%x",
1226 cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, cdb[2]);
1227
1228 switch (cdb[2] & SPC_LOG_PAGE_MASK) {
1229 case 0:
1230 if ((v = malloc(sizeof (p))) == NULL) {
1231 trans_send_complete(cmd, STATUS_BUSY);
1232 return;
1233 }
1234 bzero(&p, sizeof (p));
1235 p.length[0] = 1;
1236 bcopy(&p, v, sizeof (p));
1237 if (trans_send_datain(cmd, (char *)v, sizeof (p), 0, free,
1238 True, (emul_handle_t)v) == False) {
1239 trans_send_complete(cmd, STATUS_BUSY);
1240 }
1241 break;
1242
1243 default:
1244 spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
1245 spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0);
1246 trans_send_complete(cmd, STATUS_CHECK);
1247 break;
1248 }
1249 }
1250
1251 /*
1252 * []------------------------------------------------------------------[]
1253 * | Support functions for the SSC command set |
1254 * []------------------------------------------------------------------[]
1255 */
1256 static uint32_t
1257 find_last_obj_id(char *file_mark, off_t eod)
1258 {
1259 ssc_obj_mark_t rm;
1260 off_t offset = sizeof (ssc_obj_mark_t);
1261 uint32_t obj_id = 0xffffffff;
1262
1263 bcopy(file_mark + offset, &rm, sizeof (rm));
1264 while (rm.som_type == SSC_OBJ_TYPE_RM) {
1265 obj_id = rm.o_rm.obj_id;
1266 offset += rm.o_rm.size;
1267 if (offset >= eod)
1268 break;
1269 bcopy(file_mark + offset, &rm, sizeof (rm));
1270 }
1271 return (obj_id);
1272 }
1273
1274 static void
1275 ssc_setup_tape(ssc_params_t *s, t10_lu_common_t *lu)
1276 {
1277 ssc_obj_mark_t mark;
1278
1279 /*
1280 * Add Begin-of-Partition marker
1281 */
1282 bzero(&mark, sizeof (mark));
1283 mark.som_sig = SSC_OBJ_SIG;
1284 mark.som_type = SSC_OBJ_TYPE_FM;
1285 mark.o_fm.bom = True;
1286 mark.o_fm.eom = False;
1287 mark.o_fm.size = s->s_size - sizeof (mark);
1288 bcopy(&mark, lu->l_mmap, sizeof (mark));
1289
1290 /*
1291 * Add first file-record with a zero size.
1292 */
1293 bzero(&mark, sizeof (mark));
1294 mark.som_sig = SSC_OBJ_SIG;
1295 mark.som_type = SSC_OBJ_TYPE_RM;
1296 mark.o_rm.size = 0;
1297 mark.o_rm.obj_id = 0xffffffff;
1298 bcopy(&mark, (char *)lu->l_mmap + sizeof (ssc_obj_mark_t),
1299 sizeof (mark));
1300
1301 /*
1302 * Add End-of-Partiton marker
1303 */
1304 bzero(&mark, sizeof (mark));
1305 mark.som_sig = SSC_OBJ_SIG;
1306 mark.som_type = SSC_OBJ_TYPE_FM;
1307 mark.o_fm.bom = False;
1308 mark.o_fm.eom = True;
1309 mark.o_fm.size = 0;
1310 bcopy(&mark, (char *)lu->l_mmap + s->s_size - sizeof (mark),
1311 sizeof (mark));
1312 }
1313
1314 static char *
1315 sense_compression(ssc_params_t *s, char *data)
1316 {
1317 ssc_data_compression_t d;
1318
1319 bzero(&d, sizeof (d));
1320 d.mode_page.code = MODE_SENSE_COMPRESSION;
1321 d.mode_page.length = sizeof (d) - sizeof (struct mode_page);
1322 bcopy(&d, data, sizeof (d));
1323
1324 return (data + sizeof (d));
1325 }
1326
1327 static char *
1328 sense_dev_config(ssc_params_t *s, char *data)
1329 {
1330 ssc_device_config_t d;
1331
1332 bzero(&d, sizeof (d));
1333 d.mode_page.code = MODE_SENSE_DEV_CONFIG;
1334 d.mode_page.length = sizeof (d) - sizeof (struct mode_page);
1335 d.lois = 1;
1336 d.socf = 1;
1337 d.rewind_on_reset = 1;
1338 bcopy(&d, data, sizeof (d));
1339
1340 return (data + sizeof (d));
1341 }
1342
1343 static void
1344 ssc_free(emul_handle_t e)
1345 {
1346 free(e);
1347 }
1348
1349 /*
1350 * []----
1351 * | Command table for SSC emulation. This is at the end of the file because
1352 * | it's big and ugly. ;-) To make for fast translation to the appropriate
1353 * | emulation routine we just have a big command table with all 256 possible
1354 * | entries. Most will report STATUS_CHECK, unsupport operation. By doing
1355 * | this we can avoid error checking for command range.
1356 * []----
1357 */
1358 static scsi_cmd_table_t ssc_table[] = {
1359 /* 0x00 -- 0x0f */
1360 { spc_tur, NULL, NULL, "TEST_UNIT_READY" },
1361 { ssc_rewind, NULL, NULL, "REWIND"},
1362 { spc_unsupported, NULL, NULL, NULL },
1363 { spc_request_sense, NULL, NULL, "REQUEST_SENSE" },
1364 { spc_unsupported, NULL, NULL, NULL },
1365 { ssc_read_limits, NULL, NULL, "READ BLOCK LIMITS"},
1366 { spc_unsupported, NULL, NULL, NULL },
1367 { spc_unsupported, NULL, NULL, NULL },
1368 { ssc_read, NULL, ssc_read_cmplt, "READ(6)" },
1369 { spc_unsupported, NULL, NULL, NULL },
1370 { ssc_write, ssc_write_data, ssc_write_cmplt, "WRITE(6)" },
1371 { spc_unsupported, NULL, NULL, NULL },
1372 { spc_unsupported, NULL, NULL, NULL },
1373 { spc_unsupported, NULL, NULL, NULL },
1374 { spc_unsupported, NULL, NULL, NULL },
1375 { spc_unsupported, NULL, NULL, NULL },
1376
1377 /* 0x10 -- 0x1f */
1378 { ssc_write_fm, NULL, NULL, "WRITE_FILEMARKS(6)"},
1379 { ssc_space, NULL, NULL, "SPACE(6)"},
1380 { spc_inquiry, NULL, NULL, "INQUIRY" },
1381 { spc_unsupported, NULL, NULL, NULL },
1382 { spc_unsupported, NULL, NULL, NULL },
1383 { spc_mselect, spc_mselect_data, NULL, "MODE_SELECT(6)" },
1384 { spc_request_sense, NULL, NULL, "RESERVE" },
1385 { spc_request_sense, NULL, NULL, "RELEASE" },
1386 { spc_unsupported, NULL, NULL, NULL },
1387 { ssc_erase, NULL, NULL, "ERASE(6)"},
1388 { ssc_msense, NULL, NULL, "MODE_SENSE(6)" },
1389 { ssc_load, NULL, NULL, "LOAD_UNLOAD" },
1390 { spc_unsupported, NULL, NULL, NULL },
1391 { spc_send_diag, NULL, NULL, "SEND_DIAG" },
1392 { spc_unsupported, NULL, NULL, NULL },
1393 { spc_unsupported, NULL, NULL, NULL },
1394
1395 /* 0x20 -- 0x2f */
1396 { spc_unsupported, NULL, NULL, NULL },
1397 { spc_unsupported, NULL, NULL, NULL },
1398 { spc_unsupported, NULL, NULL, NULL },
1399 { spc_unsupported, NULL, NULL, NULL },
1400 { spc_unsupported, NULL, NULL, NULL },
1401 { spc_unsupported, NULL, NULL, "READ_CAPACITY" },
1402 { spc_unsupported, NULL, NULL, NULL },
1403 { spc_unsupported, NULL, NULL, NULL },
1404 { ssc_read, NULL, ssc_read_cmplt, "READ_G1" },
1405 { spc_unsupported, NULL, NULL, NULL },
1406 { ssc_write, ssc_write_data, ssc_write_cmplt, "WRITE_G1" },
1407 { ssc_locate, NULL, NULL, "LOCATE(10)"},
1408 { spc_unsupported, NULL, NULL, NULL },
1409 { spc_unsupported, NULL, NULL, NULL },
1410 { spc_unsupported, NULL, NULL, NULL },
1411 { spc_unsupported, NULL, NULL, NULL },
1412
1413 /* 0x30 -- 0x3f */
1414 { spc_unsupported, NULL, NULL, NULL },
1415 { spc_unsupported, NULL, NULL, NULL },
1416 { spc_unsupported, NULL, NULL, NULL },
1417 { spc_unsupported, NULL, NULL, NULL },
1418 { ssc_read_pos, NULL, NULL, "READ POSITION"},
1419 { spc_unsupported, NULL, NULL, "SYNC_CACHE" },
1420 { spc_unsupported, NULL, NULL, NULL },
1421 { spc_unsupported, NULL, NULL, NULL },
1422 { spc_unsupported, NULL, NULL, NULL },
1423 { spc_unsupported, NULL, NULL, NULL },
1424 { spc_unsupported, NULL, NULL, NULL },
1425 { spc_unsupported, NULL, NULL, NULL },
1426 { spc_unsupported, NULL, NULL, NULL },
1427 { spc_unsupported, NULL, NULL, NULL },
1428 { spc_unsupported, NULL, NULL, NULL },
1429 { spc_unsupported, NULL, NULL, NULL },
1430
1431 /* 0x40 -- 0x4f */
1432 { spc_unsupported, NULL, NULL, NULL },
1433 { spc_unsupported, NULL, NULL, NULL },
1434 { spc_unsupported, NULL, NULL, NULL },
1435 { spc_unsupported, NULL, NULL, NULL },
1436 { ssc_rpt_density, NULL, NULL, "REPORT DENSITY SUPPORT"},
1437 { spc_unsupported, NULL, NULL, NULL },
1438 { spc_unsupported, NULL, NULL, NULL },
1439 { spc_unsupported, NULL, NULL, NULL },
1440 { spc_unsupported, NULL, NULL, NULL },
1441 { spc_unsupported, NULL, NULL, NULL },
1442 { spc_unsupported, NULL, NULL, NULL },
1443 { spc_unsupported, NULL, NULL, NULL },
1444 { spc_unsupported, NULL, NULL, NULL },
1445 { ssc_logsense, NULL, NULL, "LOG SENSE" },
1446 { spc_unsupported, NULL, NULL, NULL },
1447 { spc_unsupported, NULL, NULL, NULL },
1448
1449 /* 0x50 -- 0x5f */
1450 { spc_unsupported, NULL, NULL, NULL },
1451 { spc_unsupported, NULL, NULL, NULL },
1452 { spc_unsupported, NULL, NULL, NULL },
1453 { spc_unsupported, NULL, NULL, NULL },
1454 { spc_unsupported, NULL, NULL, NULL },
1455 { spc_unsupported, NULL, NULL, NULL },
1456 { spc_unsupported, NULL, NULL, NULL },
1457 { spc_unsupported, NULL, NULL, NULL },
1458 { spc_unsupported, NULL, NULL, NULL },
1459 { spc_unsupported, NULL, NULL, NULL },
1460 { spc_unsupported, NULL, NULL, NULL },
1461 { spc_unsupported, NULL, NULL, NULL },
1462 { spc_unsupported, NULL, NULL, NULL },
1463 { spc_unsupported, NULL, NULL, NULL },
1464 { spc_unsupported, NULL, NULL, NULL },
1465 { spc_unsupported, NULL, NULL, NULL },
1466
1467 /* 0x60 -- 0x6f */
1468 { spc_unsupported, NULL, NULL, NULL },
1469 { spc_unsupported, NULL, NULL, NULL },
1470 { spc_unsupported, NULL, NULL, NULL },
1471 { spc_unsupported, NULL, NULL, NULL },
1472 { spc_unsupported, NULL, NULL, NULL },
1473 { spc_unsupported, NULL, NULL, NULL },
1474 { spc_unsupported, NULL, NULL, NULL },
1475 { spc_unsupported, NULL, NULL, NULL },
1476 { spc_unsupported, NULL, NULL, NULL },
1477 { spc_unsupported, NULL, NULL, NULL },
1478 { spc_unsupported, NULL, NULL, NULL },
1479 { spc_unsupported, NULL, NULL, NULL },
1480 { spc_unsupported, NULL, NULL, NULL },
1481 { spc_unsupported, NULL, NULL, NULL },
1482 { spc_unsupported, NULL, NULL, NULL },
1483 { spc_unsupported, NULL, NULL, NULL },
1484
1485 /* 0x70 -- 0x7f */
1486 { spc_unsupported, NULL, NULL, NULL },
1487 { spc_unsupported, NULL, NULL, NULL },
1488 { spc_unsupported, NULL, NULL, NULL },
1489 { spc_unsupported, NULL, NULL, NULL },
1490 { spc_unsupported, NULL, NULL, NULL },
1491 { spc_unsupported, NULL, NULL, NULL },
1492 { spc_unsupported, NULL, NULL, NULL },
1493 { spc_unsupported, NULL, NULL, NULL },
1494 { spc_unsupported, NULL, NULL, NULL },
1495 { spc_unsupported, NULL, NULL, NULL },
1496 { spc_unsupported, NULL, NULL, NULL },
1497 { spc_unsupported, NULL, NULL, NULL },
1498 { spc_unsupported, NULL, NULL, NULL },
1499 { spc_unsupported, NULL, NULL, NULL },
1500 { spc_unsupported, NULL, NULL, NULL },
1501 { spc_unsupported, NULL, NULL, NULL },
1502
1503 /* 0x80 -- 0x8f */
1504 { ssc_write_fm, NULL, NULL, "WRITE_FILEMARKS(16)"},
1505 { spc_unsupported, NULL, NULL, NULL },
1506 { spc_unsupported, NULL, NULL, NULL },
1507 { spc_unsupported, NULL, NULL, NULL },
1508 { spc_unsupported, NULL, NULL, NULL },
1509 { spc_unsupported, NULL, NULL, NULL },
1510 { spc_unsupported, NULL, NULL, NULL },
1511 { spc_unsupported, NULL, NULL, NULL },
1512 { ssc_read, NULL, ssc_read_cmplt, "READ_G4" },
1513 { spc_unsupported, NULL, NULL, NULL },
1514 { ssc_write, ssc_write_data, ssc_write_cmplt, "WRITE_G4" },
1515 { spc_unsupported, NULL, NULL, NULL },
1516 { spc_unsupported, NULL, NULL, NULL },
1517 { spc_unsupported, NULL, NULL, NULL },
1518 { spc_unsupported, NULL, NULL, NULL },
1519 { spc_unsupported, NULL, NULL, NULL },
1520
1521 /* 0x90 -- 0x9f */
1522 { spc_unsupported, NULL, NULL, NULL },
1523 { spc_unsupported, NULL, NULL, NULL },
1524 { ssc_locate, NULL, NULL, "LOCATE(16)"},
1525 { ssc_erase, NULL, NULL, "ERASE" },
1526 { spc_unsupported, NULL, NULL, NULL },
1527 { spc_unsupported, NULL, NULL, NULL },
1528 { spc_unsupported, NULL, NULL, NULL },
1529 { spc_unsupported, NULL, NULL, NULL },
1530 { spc_unsupported, NULL, NULL, NULL },
1531 { spc_unsupported, NULL, NULL, NULL },
1532 { spc_unsupported, NULL, NULL, NULL },
1533 { spc_unsupported, NULL, NULL, NULL },
1534 { spc_unsupported, NULL, NULL, NULL },
1535 { spc_unsupported, NULL, NULL, NULL },
1536 { spc_unsupported, NULL, NULL, "SVC_ACTION_G4" },
1537 { spc_unsupported, NULL, NULL, NULL },
1538
1539 /* 0xa0 - 0xaf */
1540 { spc_report_luns, NULL, NULL, "REPORT_LUNS" },
1541 { spc_unsupported, NULL, NULL, NULL },
1542 { spc_unsupported, NULL, NULL, NULL },
1543 { spc_report_tpgs, NULL, NULL, "REPORT_TPGS" },
1544 { spc_unsupported, NULL, NULL, NULL },
1545 { spc_unsupported, NULL, NULL, NULL },
1546 { spc_unsupported, NULL, NULL, NULL },
1547 { spc_unsupported, NULL, NULL, NULL },
1548 { spc_unsupported, NULL, NULL, NULL },
1549 { spc_unsupported, NULL, NULL, NULL },
1550 { spc_unsupported, NULL, NULL, NULL },
1551 { spc_unsupported, NULL, NULL, NULL },
1552 { spc_unsupported, NULL, NULL, NULL },
1553 { spc_unsupported, NULL, NULL, NULL },
1554 { spc_unsupported, NULL, NULL, NULL },
1555 { spc_unsupported, NULL, NULL, NULL },
1556
1557 /* 0xb0 -- 0xbf */
1558 { spc_unsupported, NULL, NULL, NULL },
1559 { spc_unsupported, NULL, NULL, NULL },
1560 { spc_unsupported, NULL, NULL, NULL },
1561 { spc_unsupported, NULL, NULL, NULL },
1562 { spc_unsupported, NULL, NULL, NULL },
1563 { spc_unsupported, NULL, NULL, NULL },
1564 { spc_unsupported, NULL, NULL, NULL },
1565 { spc_unsupported, NULL, NULL, NULL },
1566 { spc_unsupported, NULL, NULL, NULL },
1567 { spc_unsupported, NULL, NULL, NULL },
1568 { spc_unsupported, NULL, NULL, NULL },
1569 { spc_unsupported, NULL, NULL, NULL },
1570 { spc_unsupported, NULL, NULL, NULL },
1571 { spc_unsupported, NULL, NULL, NULL },
1572 { spc_unsupported, NULL, NULL, NULL },
1573 { spc_unsupported, NULL, NULL, NULL },
1574
1575 /* 0xc0 -- 0xcf */
1576 { spc_unsupported, NULL, NULL, NULL },
1577 { spc_unsupported, NULL, NULL, NULL },
1578 { spc_unsupported, NULL, NULL, NULL },
1579 { spc_unsupported, NULL, NULL, NULL },
1580 { spc_unsupported, NULL, NULL, NULL },
1581 { spc_unsupported, NULL, NULL, NULL },
1582 { spc_unsupported, NULL, NULL, NULL },
1583 { spc_unsupported, NULL, NULL, NULL },
1584 { spc_unsupported, NULL, NULL, NULL },
1585 { spc_unsupported, NULL, NULL, NULL },
1586 { spc_unsupported, NULL, NULL, NULL },
1587 { spc_unsupported, NULL, NULL, NULL },
1588 { spc_unsupported, NULL, NULL, NULL },
1589 { spc_unsupported, NULL, NULL, NULL },
1590 { spc_unsupported, NULL, NULL, NULL },
1591 { spc_unsupported, NULL, NULL, NULL },
1592
1593 /* 0xd0 -- 0xdf */
1594 { spc_unsupported, NULL, NULL, NULL },
1595 { spc_unsupported, NULL, NULL, NULL },
1596 { spc_unsupported, NULL, NULL, NULL },
1597 { spc_unsupported, NULL, NULL, NULL },
1598 { spc_unsupported, NULL, NULL, NULL },
1599 { spc_unsupported, NULL, NULL, NULL },
1600 { spc_unsupported, NULL, NULL, NULL },
1601 { spc_unsupported, NULL, NULL, NULL },
1602 { spc_unsupported, NULL, NULL, NULL },
1603 { spc_unsupported, NULL, NULL, NULL },
1604 { spc_unsupported, NULL, NULL, NULL },
1605 { spc_unsupported, NULL, NULL, NULL },
1606 { spc_unsupported, NULL, NULL, NULL },
1607 { spc_unsupported, NULL, NULL, NULL },
1608 { spc_unsupported, NULL, NULL, NULL },
1609 { spc_unsupported, NULL, NULL, NULL },
1610
1611 /* 0xe0 -- 0xef */
1612 { spc_unsupported, NULL, NULL, NULL },
1613 { spc_unsupported, NULL, NULL, NULL },
1614 { spc_unsupported, NULL, NULL, NULL },
1615 { spc_unsupported, NULL, NULL, NULL },
1616 { spc_unsupported, NULL, NULL, NULL },
1617 { spc_unsupported, NULL, NULL, NULL },
1618 { spc_unsupported, NULL, NULL, NULL },
1619 { spc_unsupported, NULL, NULL, NULL },
1620 { spc_unsupported, NULL, NULL, NULL },
1621 { spc_unsupported, NULL, NULL, NULL },
1622 { spc_unsupported, NULL, NULL, NULL },
1623 { spc_unsupported, NULL, NULL, NULL },
1624 { spc_unsupported, NULL, NULL, NULL },
1625 { spc_unsupported, NULL, NULL, NULL },
1626 { spc_unsupported, NULL, NULL, NULL },
1627 { spc_unsupported, NULL, NULL, NULL },
1628
1629 /* 0xf0 -- 0xff */
1630 { spc_unsupported, NULL, NULL, NULL },
1631 { spc_unsupported, NULL, NULL, NULL },
1632 { spc_unsupported, NULL, NULL, NULL },
1633 { spc_unsupported, NULL, NULL, NULL },
1634 { spc_unsupported, NULL, NULL, NULL },
1635 { spc_unsupported, NULL, NULL, NULL },
1636 { spc_unsupported, NULL, NULL, NULL },
1637 { spc_unsupported, NULL, NULL, NULL },
1638 { spc_unsupported, NULL, NULL, NULL },
1639 { spc_unsupported, NULL, NULL, NULL },
1640 { spc_unsupported, NULL, NULL, NULL },
1641 { spc_unsupported, NULL, NULL, NULL },
1642 { spc_unsupported, NULL, NULL, NULL },
1643 { spc_unsupported, NULL, NULL, NULL },
1644 { spc_unsupported, NULL, NULL, NULL },
1645 { spc_unsupported, NULL, NULL, NULL },
1646 };