t10_ssc.c revision 36c5fee33fa8b822175d410202aebcf592c8d342
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Implementation of SSC-2 emulation
*/
#include <strings.h>
#include <unistd.h>
#include <aio.h>
#include "target.h"
#include "utility.h"
#include "t10.h"
#include "t10_spc.h"
#include "t10_ssc.h"
/*
* []----
* | Forward declarations
* []----
*/
static scsi_cmd_table_t ssc_table[];
static void ssc_free(emul_handle_t e);
static void ssc_write_cmplt(emul_handle_t e);
/*
* []----
* | ssc_init_common -- initialize common information that all ITLs will use
* []----
*/
{
ssc_params_t *s;
return (False);
return (False);
ssc_setup_tape(s, lu);
}
s->s_cur_fm = 0;
s->s_cur_rec = sizeof (ssc_obj_mark_t);
s->s_prev_rec = s->s_cur_rec;
lu->l_dtype_params = (void *)s;
return (True);
}
/*
* []----
* | ssc_fini_common -- free any resources
* []----
*/
void
{
}
void
{
switch (op) {
case CapacityChange:
break;
case DeviceOnline:
}
}
/*
* []----
* | ssc_init_per -- initialize per ITL information
* []----
*/
void
{
else
}
/*
* []----
* | ssc_fini_per -- release or free any ITL resources
* []----
*/
/*ARGSUSED*/
void
{
}
/*
* []----
* | ssc_cmd -- start a SCSI command
* |
* | This routine is called from within the SAM-3 Task router.
* []----
*/
static void
{
scsi_cmd_table_t *e;
#ifdef FULL_DEBUG
#endif
}
/*
* []----
* | ssc_data -- Data phase for command.
* |
* | Normally this is only called for the WRITE command. Other commands
* | that have a data in phase will probably be short circuited when
* | we call trans_rqst_dataout() and the data is already available.
* | At least this is true for iSCSI. FC however will need a DataIn phase
* | for commands like MODE SELECT and PGROUT.
* []----
*/
static void
{
scsi_cmd_table_t *e;
#ifdef FULL_DEBUG
e->cmd_name);
#endif
}
/*
* []------------------------------------------------------------------[]
* | SCSI Streaming Commands - 3 |
* | T10/1611-D Revision 01c |
* | The following functions implement the emulation of SSC-3 type |
* | commands. |
* []------------------------------------------------------------------[]
*/
/*ARGSUSED*/
static void
{
rm;
int fixed,
sili;
if (s == NULL)
return;
/*
* Standard error checking.
*/
return;
}
if (req_len == 0) {
return;
}
#ifdef FULL_DEBUG
"SSC%x LUN%d read 0x%x bytes",
#endif
"SSC%x LUN%d bad RECORD-MARK",
return;
s->s_cur_rec = sizeof (ssc_obj_mark_t);
s->s_prev_rec = s->s_cur_rec;
return;
} else if ((sili == 0) &&
"SSC%x LUN%d Wrong size read",
s->s_prev_rec = s->s_cur_rec;
return;
}
do {
return;
}
s->s_prev_rec = s->s_cur_rec;
}
static void
{
return;
}
}
} else {
}
}
}
/*ARGSUSED*/
static void
{
int fixed,
if (s == NULL)
return;
return;
}
#ifdef FULL_DEBUG
"SSC%x LUN%d write %d, fixed %d",
request_len, fixed);
#endif
return;
}
io->sio_offset = 0;
/*
* Writing looses all information after the current
* file-mark. So, check to see if the current file-mark
* size doesn't reflect the end-of-media. If not, update
* it.
*/
s->s_cur_fm;
}
/*
* End-of-Partition detection
*/
return;
}
if ((s->s_cur_fm == 0) &&
(s->s_cur_rec == sizeof (ssc_obj_mark_t))) {
/*
* The current position is a BOM. By setting
* the prev_id value to -1 the code below will
* create the first ID with a value of zero
* Which is what the specification requires.
*/
prev_id = -1;
} else if (s->s_cur_rec == sizeof (ssc_obj_mark_t)) {
/*
* If the current position is at the beginning of
* this file-mark use the object ID found in
* the file-mark header. It will have been updated
* from the last object ID in the previous file-mark.
*
* NOTE: We're counting on 'mark' still referring
* to the current file mark here.
*/
} else {
}
sizeof (ssc_obj_mark_t);
}
}
}
/*ARGSUSED*/
static void
{
if (s == NULL)
return;
if (s->s_fast_write_ack == False) {
/*
* We only need to worry about sync'ing the blocks
* in the mmap case because if the fast cache isn't
* enabled for AIO the file will be opened with F_SYNC
* which performs the correct action.
*/
return;
}
}
}
static void
{
if (s == NULL)
return;
return;
}
s->s_prev_rec = s->s_cur_rec;
}
/*ARGSUSED*/
static void
{
if (s == NULL)
return;
return;
}
s->s_cur_fm = 0;
s->s_cur_rec = sizeof (ssc_obj_mark_t);
}
/*ARGSUSED*/
static void
{
struct read_blklim *rb;
int min_size = 512;
return;
}
return;
}
/*
* maximum block size is set to zero to indicate no maximum block
* limit is specified.
*/
}
}
/*ARGSUSED*/
static void
{
int code,
if (s == NULL)
return;
return;
}
return;
}
switch (code) {
case SSC_SPACE_CODE_BLOCKS:
if (count < 0) {
/*
* If the count is still negative it means
* the request is still attempting to go
* beyond the beginning of the file mark.
*/
if (count < 0) {
count *= -1;
return;
}
} else {
/*
* Something is not right. We'll let the
* processing below determine exactly what
* is wrong. So don't update the record
* mark and sent the count to 1.
*/
count = 1;
}
}
while (count) {
/*
* Something internally bad has happened with
* the marks in the file.
*/
"SSC%x LUN%d, bad sig mark: "
"expected=0x%x, got=0x%x",
return;
}
/*
* Hit a filemark. Update the current record if
* we're not at the End-Of-Medium.
*/
0);
return;
}
return;
}
count--;
}
break;
case SSC_SPACE_CODE_FILEMARKS:
if (count < 0) {
sizeof (mark));
/*
* If the count is still negative it means
* the request is still attempting to go
* beyond the beginning of the file mark.
*/
if (count < 0) {
count *= -1;
return;
}
s->s_cur_fm = 0;
s->s_cur_rec = sizeof (ssc_obj_mark_t);
} else {
/*
* Something is not right. We'll let the
* processing below determine exactly what
* is wrong. So don't update the record
* mark and sent the count to 1.
*/
count = 1;
}
}
while (count--) {
sizeof (mark));
"SSC%x LUN%d, bad sig mark: "
"expected=0x%x, got=0x%x",
return;
}
"SSC%x LUN%d, bad mark type: "
"expected=0x%x, got=0x%x",
return;
}
return;
}
}
break;
default:
return;
}
}
/*
* []----
* | ssc_msense -- MODE SENSE command
* |
* | This command is part of the SPC set, but is device specific enough
* | that it must be emulated in each device type.
* []----
*/
/*ARGSUSED*/
static void
{
struct mode_header *mode_hdr;
int request_len,
char *data,
*np;
/*
* SPC-3 Revision 21c section 6.8
* Reserve bit checks
*/
return;
}
/*
* Zero length causes a simple ack to occur.
*/
if (cdb[4] == 0) {
return;
} else {
sizeof (*mode_hdr) + MODE_BLK_DESC_LENGTH +
sizeof (ssc_data_compression_t) + sizeof (*mode_hdr) +
MODE_BLK_DESC_LENGTH + sizeof (ssc_device_config_t));
}
return;
}
switch (cdb[2]) {
case MODE_SENSE_COMPRESSION:
break;
case MODE_SENSE_DEV_CONFIG:
break;
case MODE_SENSE_SEND_ALL:
(void) sense_dev_config(s, np);
break;
case 0x00:
break;
default:
"SSC%x LUN%d: MODE SENSE(0x%x) not handled",
cdb[2]);
return;
}
}
}
/*ARGSUSED*/
static void
{
int service_action,
void *data;
if (s == NULL)
return;
/*
* Standard reserve bit check
*/
return;
}
switch (service_action) {
case SSC_READ_POS_SHORT_FORM:
return;
}
(s->s_cur_rec == sizeof (ssc_obj_mark_t)))
/*
* We mark the last object to be the same as the first
* object which indicates that nothing is currently
* buffered.
*/
break;
case SSC_READ_POS_LONG_FORM:
return;
default:
return;
}
}
}
/*ARGSUSED*/
static void
{
ssc_density_t *d;
int medium_type,
void *data;
if (s == NULL)
return;
return;
}
return;
}
if (medium_type == 0) {
d = (ssc_density_t *)data;
sizeof (ssc_density_header_t));
d->d_prim_code = 1;
d->d_wrtok = 1;
d->d_deflt = 1;
min(sizeof (d->d_organization),
min(sizeof (d->d_description),
} else {
sizeof (ssc_density_header_t));
min(sizeof (d->d_organization),
}
}
}
/*ARGSUSED*/
static void
{
int marks_requested;
if (s == NULL)
return;
return;
}
while (marks_requested--) {
/*
* Get the last file-mark and update it's size.
*/
return;
}
/*
* Write new mark and update internal location of mark.
*/
s->s_cur_rec = sizeof (ssc_obj_mark_t);
s->s_prev_rec = s->s_cur_rec;
}
}
/*ARGSUSED*/
static void
{
}
/*ARGSUSED*/
static void
{
if (s == NULL)
return;
}
/*ARGSUSED*/
static void
{
/*
* Check for various reserve bits.
*/
return;
}
/*
* There are four possible actions based on the LOAD and HOLD
* bits.
*/
/*
* Load the media into the system if not already done
* so, but do not position tape. The EOT and RETEN should
* be zero. Since this emulation currently is always available
* we're good to go.
*/
break;
case SSC_LOAD_CMD_LOAD:
/*
* Without the HOLD bit the tape should be positioned at
* the beginning of partition 0.
*/
s->s_cur_fm = 0;
s->s_cur_rec = sizeof (ssc_obj_mark_t);
break;
case SSC_LOAD_CMD_HOLD:
/*
* Without the LOAD bit we leave the tape online, but look
* at the RETEN and EOT bits. The RETEN doesn't mean anything
* for this virtual tape, but we can reposition to EOT.
*/
/*CONSTANTCONDITION*/
while (1) {
sizeof (mark));
"SSC%x LUN%d, bad sig mark: "
"expected=0x%x, got=0x%x",
KEY_MEDIUM_ERROR, 0);
return;
}
"SSC%x LUN%d, bad mark type: "
"expected=0x%x, got=0x%x",
KEY_MEDIUM_ERROR, 0);
return;
}
break;
}
}
break;
case 0:
/*
* Unload the current tape.
*/
break;
}
}
/*ARGSUSED*/
static void
{
void *v;
/*
* Reserve bit checks
*/
return;
}
case 0:
return;
}
bzero(&p, sizeof (p));
p.length[0] = 1;
bcopy(&p, v, sizeof (p));
}
break;
default:
break;
}
}
/*
* []------------------------------------------------------------------[]
* | Support functions for the SSC command set |
* []------------------------------------------------------------------[]
*/
static uint32_t
{
break;
}
return (obj_id);
}
static void
{
/*
* Add Begin-of-Partition marker
*/
/*
* Add first file-record with a zero size.
*/
sizeof (mark));
/*
* Add End-of-Partiton marker
*/
sizeof (mark));
}
static char *
{
bzero(&d, sizeof (d));
return (data + sizeof (d));
}
static char *
{
bzero(&d, sizeof (d));
d.lois = 1;
d.socf = 1;
d.rewind_on_reset = 1;
return (data + sizeof (d));
}
static void
{
free(e);
}
/*
* []----
* | Command table for SSC emulation. This is at the end of the file because
* | it's big and ugly. ;-) To make for fast translation to the appropriate
* | emulation routine we just have a big command table with all 256 possible
* | entries. Most will report STATUS_CHECK, unsupport operation. By doing
* | this we can avoid error checking for command range.
* []----
*/
static scsi_cmd_table_t ssc_table[] = {
/* 0x00 -- 0x0f */
/* 0x10 -- 0x1f */
/* 0x20 -- 0x2f */
/* 0x30 -- 0x3f */
/* 0x40 -- 0x4f */
/* 0x50 -- 0x5f */
/* 0x60 -- 0x6f */
/* 0x70 -- 0x7f */
/* 0x80 -- 0x8f */
/* 0x90 -- 0x9f */
/* 0xa0 - 0xaf */
/* 0xb0 -- 0xbf */
/* 0xc0 -- 0xcf */
/* 0xd0 -- 0xdf */
/* 0xe0 -- 0xef */
/* 0xf0 -- 0xff */
};