t10_spc.c revision 2cb5f2d8d3edf24c4304283afef8e0558d839bbd
/*
* 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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* []------------------------------------------------------------------[]
* | SPC-3 Support Functions |
* | These routines are not directly called by the SAM-3 layer. Those |
* | who write device emulation modules are free to call these routine |
* | to carry out housekeeping chores. |
* []------------------------------------------------------------------[]
*/
#include <strings.h>
#include <unistd.h>
#include "t10.h"
#include "t10_spc.h"
#include "target.h"
/*
* []----
* | spc_unsupported -- generic routine to indicate we don't support this cmd
* []----
*/
/*ARGSUSED*/
void
{
char debug[80];
"SAM%d LUN%d Command 0x%x (%s) unsupported\n",
}
/*
* []----
* | spc_tur -- test unit ready
* []----
*/
/*ARGSUSED*/
void
{
/*
* SPC-3 Revision 21c, section 6.31
* Reserve bit checks
*/
} else
}
/*
* []----
* | spc_request_sense --
* []----
*/
/*ARGSUSED*/
void
{
/* ---- Check for reserved bit conditions ---- */
} else {
/*
* Since we always run with autosense enabled there's
* no sense data to return. That may change in the future
* if we decide to add such support, but for now return
* success always.
*/
spc_sense_create(cmd, 0, 0);
}
}
/*
* []----
* | spc_inquiry -- Standard INQUIRY command
* []----
*/
/*ARGSUSED*/
void
{
*rbp; /* temporary var */
struct scsi_inquiry *inq;
void *v;
/*
* Information obtained from:
* SPC-3 Revision 21c
* Section 6.4.1 INQUIRY command
* Need to generate a CHECK CONDITION with ILLEGAL REQUEST
* and INVALID FIELD IN CDB (0x24/0x00) if any of the following is
* true.
* (1) If the EVPD bit is not set, then the page code must be zero.
* (2) If any bit other than EVPD is set.
* (3) If any of the reserved bits in the CONTROL byte are set.
*/
return;
}
/*
* Zero length is not an error and we should just acknowledge
* the operation.
*/
if (rqst_len == 0) {
return;
}
/*
* We send back a total of six Vital Product Data descriptors
* plus associated data. Three are EUI values, two are for AULA
* support being simple 4 byte values, and one is the IQN string.
* NOTE: The IQN string is just an artifact of when the target
* was created. Once FC support is added, the t_name would be
* either a "naa." or "eui." string.
*/
/*
* We always allocate enough space so that the code can create
* either the full inquiry data or page 0x83 data.
*/
/*
* Allocate space with an alignment that will work for any casting.
*/
return;
}
/*
* EVPD not set returns the standard inquiry data.
*/
if (cdb[1] == 0) {
/*
* Return whatever is the smallest amount between the
* INQUIRY data or the amount requested.
*/
/*
* SPC-3 Revision 21c, Section 6.4.2 .. Table 82 -- Version
* This target will comply with T10/1416-D
*/
inq->inq_normaca = 0;
inq->inq_linked = 0;
/*
* JIST Requires that we show support for hierarchical
* support (HiSup).
*/
/*
* SPC-4, revision 1a, section 6.4.2
* Stand INQUIRY Data
* To support MPxIO we enable ALUA support and identify
* we defaults to symmertrical devices.
*/
/*
* SPC-3 Revision 21c, section 6.4.2
* Table 85 -- Version Descriptor values
* Starting at byte 58 there are up to 8 version
* descriptors which are 16bits in size.
*
* NOTE: The ordering of these values is according
* to the standard. First comes the architectural
* version and then followed by: physical transport,
* SCSI transport, primary command set version, and
* finally the device type command set.
*/
/* SAM-3 T10/1561-D rev 14 */
/* physical transport code unknown */
/* SPC ANSI X3.301:1997 */
/* SBC-2 T10/1417-D rev 5a */
/* SSC-2 (no version) */
/* OSD T10/1355-D revision 10 */
}
} else {
/* ---- Common information returned with all page types ---- */
switch (cdb[2]) {
default:
return;
case SPC_INQ_PAGE0:
/*
* SPC-3 Revision 21c Section 7.6.10
* EVPD page 0 returns information about which pages
* are supported. We support page 0x00 and 0x83.
* NOTE: The value found in byte[3] is the returned
* page length as defined by (n - 3) where 'n' is
* the last valid byte. In this case 5.
*/
/*
* Return the smallest amount of data between the
* requested amount and the size of the Page83 data.
*/
rsp_buf[3]);
break;
case SPC_INQ_PAGE80:
/*
* Return the smallest amount of data between the
* requested amount and the size of the Page80 data.
*/
break;
case SPC_INQ_PAGE83:
/*
* Return the smallest amount of data between the
* requested amount and the size of the Page83 data.
*/
/*
* Information obtained from:
* SPC-3 Revision 21c
* Section 7.6.4.1
*/
/* ---- VPD header ---- */
/* ---- VPD descriptor ---- */
/*
* SPC-4 revision 1a, section 7.6.3.8
* Target port group designator format
*/
/* ---- VPD descriptor ---- */
/*
* SPC-4, revision 1a, section 7.6.3.7
* Relative target port designator format
*/
/* ---- VPD descriptor ---- */
/* ---- VPD descriptor ---- */
/*
* SPC-3 revision 23, section 7.6.3.11
* Use the string length and not the scsi_len because
* we've rounded up the length to a multiple of four
* as required by the specification.
*/
/* ---- VPD descriptor ---- */
/*
* XXX Is this right XXX
* Should we be using some other name.
*/
/* ---- VPD descriptor ---- */
/*
* XXX Is this right XXX
* Should we be using some other name.
*/
/*
* rbp is updated here even though nobody will
* currently use it. Currently is the optertive word
* here. If for some reason we add another VDP
* then the pointer will be correct.
*/
break;
case SPC_INQ_PAGE86:
/*
* Return the smallest amount of data between the
* requested amount and the size of the Page86 data.
*/
eid = (extended_inq_data_t *)v;
/*
* At this point in time we don't support any of the
* extended data attributes. We should support
* the task management bits though.
*/
break;
}
}
}
}
/*
* []----
* | spc_mselect -- Generic MODE SELECT command
* []----
*/
/*ARGSUSED*/
void
{
char *buf;
/*
* SPC-3 revision 21c, section 6.7
* Reserve bit checks
*/
return;
}
if (cdb[4] == 0) {
return;
}
}
}
/*
* []----
* | spc_mselect_data -- DataIn phase of MODE SELECT command
* []----
*/
/*ARGSUSED*/
void
{
struct mode_control_scsi3 mode_ctl_page;
struct mode_header hdr;
sizeof (mode_ctl_page));
case MODE_SENSE_CONTROL:
/*
* SPC-3 revision 21c, section 7.4.6
* Table 239 describes the fields. We're only interested
* in the descriptor sense bit.
*/
} else {
}
break;
default:
return;
}
}
/*
* []----
* | spc_report_luns --
* []----
*/
/*ARGSUSED*/
void
{
int expected_data;
int entries = 0,
len,
char *str;
*lun_list,
*lun;
/*
* SPC-3 Revision 21c section 6.21
* Error checking.
*/
return;
}
if (expected_data < 16) {
/*
* The allocation length should be at least 16 according
* to SPC-3.
*/
return;
}
NULL) {
False) {
goto error;
}
break;
} else
}
if (!targ)
goto error;
goto error;
entries++;
return;
}
NULL) {
goto error;
continue;
}
}
} else {
/*
* This will return the size needed to complete this request
* and a implicit LUN zero.
*/
}
}
return;
if (buf)
}
/*ARGSUSED*/
void
{
rtpg_hdr_t *r;
int rqst_len,
i;
if (disable_tpgs == True) {
return;
}
/*
* Reserve bit checks
*/
return;
}
/*
* We only have one target port group which it's size is
* accounted for in rtpg_hdr_t. Take the number of tgts
* and subtract one since the first is accounted for in
* rtpg_targ_desc_t
*/
sizeof (rtpg_targ_desc_t)) + sizeof (rtpg_hdr_t);
/*
* Make sure that we have enough room to store everything
* that we want to, but only returned the requested about
* of data which is why d->d_len is set to the request amount.
* A client could issue a REPORT_TPGS with a length of 4 bytes
* which would be just enough to see how much space is actually
* used.
*/
if (rqst_len == 0) {
return;
}
return;
}
dp->status_code = 0;
i = SPC_DEFAULT_TPG;
do {
tp++;
}
}
/*ARGSUSED*/
void
{
/*
* SPC-3 Revision 21c, section 6.27
* Reserve bit checks
*/
return;
}
/*
* There's no diagnostics to be run at this time. So, always
* return success. If, at some point in the future, it's determined
* that something can be done which is meaningful then place the
* code here.
*/
}
static void
{
}
/*
* []----
* | spc_cmd_offline -- return IN_PROGRESS for media related commands
* |
* | During LU initialization the device is in an offline state. When
* | offlined only non-media related commands are allowed to proceed.
* | TEST_UNIT_READY is considered a media command since it must return
* | a CHECK_CONDITION if a media command would do so.
* []----
*/
void
{
scsi_cmd_table_t *e;
int old_dtype;
switch (cdb[0]) {
case SCMD_TEST_UNIT_READY:
case SCMD_START_STOP:
case SCMD_READ:
case SCMD_READ_G1:
case SCMD_READ_G4:
case SCMD_WRITE:
case SCMD_WRITE_G1:
case SCMD_WRITE_G4:
#ifdef FULL_DEBUG
#endif
break;
case SCMD_INQUIRY:
/*
* While the device is being initialized any inquiry commands
* will return an unknown device type. This will cause the
* transport to hold off further plumbing until the
* initialization is complete and we send the inventory change
* notice.
*/
break;
default:
break;
}
}
/*
* []----
* | spc_sense_create -- allocate sense structure
* |
* | If additional header sense length is requested and the I_T_Q has
* | enabled descriptor sense data allocate the space.
* []----
*/
void
{
char *buf;
int size;
/*
* It's possible under certain conditions -- namely a malloc error
* when setting up a command -- that the pointer to the ITL structure
* isn't valid. If that's the case don't attempt to dereference it
* to look at the dsense_enabled flag.
*/
struct scsi_descr_sense_hdr d;
return;
size = sizeof (d) + addl_sense_len;
bzero(&d, sizeof (d));
} else {
struct scsi_extended_sense e;
return;
size = sizeof (e);
bzero(&e, sizeof (e));
}
/* ---- First two bytes of the sense store the length ---- */
}
/*
* []----
* | spc_sense_raw -- copy an existing sense buffer for return.
* |
* | If an emulation module already has a sense buffer there's no need
* | to decode the sense data and call the various spc_sense_ routines
* | to reencode the information.
* []----
*/
void
{
return;
}
void
{
struct scsi_extended_sense s;
struct scsi_descr_sense_hdr d;
switch (s.es_code) {
case CODE_FMT_DESCR_CURRENT:
case CODE_FMT_DESCR_DEFERRED:
d.ds_add_code = asc;
d.ds_qual_code = ascq;
break;
default:
s.es_add_code = asc;
s.es_qual_code = ascq;
break;
}
}
void
{
struct scsi_information_sense_descr isd;
struct scsi_extended_sense s;
char *p;
case CODE_FMT_DESCR_CURRENT:
case CODE_FMT_DESCR_DEFERRED:
break;
case CODE_FMT_VENDOR_SPECIFIC:
case CODE_FMT_FIXED_CURRENT:
case CODE_FMT_FIXED_DEFERRED:
default:
s.es_valid = 1;
if (info > FIXED_SENSE_ADDL_INFO_LEN) {
s.es_info_1 = 0xff;
s.es_info_2 = 0xff;
s.es_info_3 = 0xff;
s.es_info_4 = 0xff;
} else {
}
break;
}
}
void
{
struct scsi_extended_sense s;
if (flags & SPC_SENSE_EOM)
s.es_eom = 1;
if (flags & SPC_SENSE_FM)
s.es_filmk = 1;
if (flags & SPC_SENSE_ILI)
s.es_ili = 1;
}
/*
* []----
* | spc_decode_lu_addr -- Decodes LU addressing as specified in SAM-3
* []----
*/
{
if (len < 2)
return (False);
switch (buf[0] & SCSI_REPORTLUNS_ADDRESS_MASK) {
break;
/*
* Since we never encode a LUN using this method, we
* shouldn't receive it back.
*/
return (False);
switch (buf[0] & SCSI_REPORTLUNS_ADDRESS_EXTENDED_MASK) {
break;
if (len < 4)
return (False);
break;
if (len < 6)
return (False);
/*
* This should be able to handle a 40-bit LUN,
* but since our LUNs are only 32-bit we don't
* bother to decode buf[1]. This is okay since
* we generate the LUN in the first place.
*/
break;
/*
* Since we current don't support larger than
* 32-bit LUNs we'll never create an extended
* address using this format. So, if we are to
* get this format in, just return an error.
*/
return (False);
break;
}
}
return (True);
}
/*
* []----
* |
* | NOTE: This routine only deals with 32-bit logical unit numbers.
* | If this program ever switches to using larger values we need to
* | simply deal with those formats.
* []----
*/
{
if (lun < 256) {
/*
* SAM-3 revision 14, Section 4.9.6.
* No bus identifier for our luns.
*/
} else if (lun < 0x3fff) {
/*
* SAM-3 revision 14, Section 4.9.7.
* 14-bit flat address space.
*/
} else if (select_field == SCSI_REPORTLUNS_SELECT_ALL) {
/*
* 32-bit limitation. This format should be able to
* handle a 40-bit LUN.
*/
buf[1] = 0;
} else
/*
* Either the user hasn't requested extended unit addressing
* or the LU is greater than 32bits. Since internally we
* only have 32bit numbers it's more likely that the initiator
* hasn't selected a correct report format.
*/
return (False);
return (True);
}