/*
* Copyright (c) 1998,1999,2000
* Traakan, Inc., Los Altos, CA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice unmodified, this list of conditions, and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Project: NDMJOB
* Ident: $Id: $
*
* Description:
*
*/
#include "ndmlib.h"
/*
* NAME[,[CNUM,]SID[,LUN]
*
* The foregoing pattern is ambiguous. Here's the disambiguating rules:
* 1) If just a name is given, controller, sid, and lun are all
* set to invalid (-1)
* 2) If one number comes after the device name (,sid) it is the
* SID; controller is set to -1, lun is set to 0
* 3) If two numbers come after the device name (,sid,lun), they are
* the SID and LUN; controller is set to -1
* 4) Three numbers after the device name are all three number fields.
*/
int
ndmscsi_target_from_str (struct ndmscsi_target *targ, char *str)
{
char * p;
int n1, n2, n3;
NDMOS_MACRO_ZEROFILL (targ);
p = strchr (str, ',');
if (p) {
*p++ = 0;
}
if (strlen (str) >= PATH_MAX) {
if (p) p[-1] = ',';
return -2;
}
strcpy (targ->dev_name, str);
if (!p) {
targ->controller = -1;
targ->sid = -1;
targ->lun = -1;
return 0;
}
p[-1] = ',';
if (*p < '0' || '9' < *p) {
return -3;
}
n1 = strtol (p, &p, 0);
if (*p != 0 && *p != ',') {
return -4;
}
if (*p == 0) {
targ->controller = -1;
targ->sid = n1;
targ->lun = 0;
return 0;
}
p++;
if (*p < '0' || '9' < *p) {
return -5;
}
n2 = strtol (p, &p, 0);
if (*p == 0) {
/* SID,LUN */
targ->controller = -1;
targ->sid = n1;
targ->lun = n2;
} else {
if (*p != ',') {
return -6;
}
p++;
if (*p < '0' || '9' < *p) {
return -7;
}
n3 = strtol (p, &p, 0);
if (*p != 0) {
return -8;
}
targ->controller = n1;
targ->sid = n2;
targ->lun = n3;
}
return 0;
}
int
ndmscsi_open (struct ndmconn *conn, char *dev_name)
{
int rc;
NDMC_WITH(ndmp9_scsi_open, NDMP9VER)
request->device = dev_name;
rc = NDMC_CALL(conn);
NDMC_ENDWITH
return rc;
}
int
ndmscsi_close (struct ndmconn *conn)
{
int rc;
NDMC_WITH_VOID_REQUEST(ndmp9_scsi_close, NDMP9VER)
rc = NDMC_CALL(conn);
NDMC_ENDWITH
return rc;
}
int
ndmscsi_get_state (struct ndmconn *conn, struct ndmscsi_target *targ)
{
int rc;
NDMOS_MACRO_ZEROFILL (targ);
NDMC_WITH_VOID_REQUEST(ndmp9_scsi_get_state, NDMP9VER)
rc = NDMC_CALL(conn);
targ->controller = reply->target_controller;
targ->sid = reply->target_id;
targ->lun = reply->target_lun;
NDMC_ENDWITH
return rc;
}
int
ndmscsi_set_target (struct ndmconn *conn, struct ndmscsi_target *targ)
{
int rc;
NDMC_WITH(ndmp9_scsi_set_target, NDMP9VER)
request->device = targ->dev_name;
request->target_controller = targ->controller;
request->target_id = targ->sid;
request->target_lun = targ->lun;
rc = NDMC_CALL(conn);
NDMC_ENDWITH
return rc;
}
int
ndmscsi_use (struct ndmconn *conn, struct ndmscsi_target *targ)
{
int rc;
#if 0
rc = ndmscsi_close (conn);
/* error ignored */
#endif
rc = ndmscsi_open (conn, targ->dev_name);
if (rc) return rc;
if (targ->controller != -1 || targ->sid != -1 || targ->lun != -1) {
#ifndef NDMOS_OPTION_NO_NDMP4
if (conn->protocol_version == NDMP4VER) {
return -1; /* can't set target */
}
#endif /* !NDMOS_OPTION_NO_NDMP4 */
rc = ndmscsi_set_target (conn, targ);
if (rc) {
ndmscsi_close (conn); /* best effort */
return rc;
}
}
return 0;
}
int
ndmscsi_execute (struct ndmconn *conn,
struct ndmscsi_request *req,
struct ndmscsi_target *targ)
{
int rc;
if (targ) {
rc = ndmscsi_use (conn, targ);
if (rc) return rc;
}
NDMC_WITH(ndmp9_scsi_execute_cdb, NDMP9VER)
request->cdb.cdb_len = req->n_cmd;
request->cdb.cdb_val = (char*)req->cmd;
switch (req->data_dir) {
case NDMSCSI_DD_NONE:
request->data_dir = NDMP9_SCSI_DATA_DIR_NONE;
break;
case NDMSCSI_DD_IN:
request->data_dir = NDMP9_SCSI_DATA_DIR_IN;
request->datain_len = req->n_data_avail;
break;
case NDMSCSI_DD_OUT:
request->data_dir = NDMP9_SCSI_DATA_DIR_OUT;
request->dataout.dataout_len = req->n_data_avail;
request->dataout.dataout_val = (char*)req->data;
break;
}
request->timeout = 300000; /* five minutes */
rc = NDMC_CALL (conn);
if (rc) {
req->completion_status = NDMSCSI_CS_FAIL;
return rc;
}
req->status_byte = reply->status;
req->n_data_done = 0;
req->n_sense_data = 0;
rc = reply->ext_sense.ext_sense_len;
if (rc > 0) {
if (rc > NDMSCSI_MAX_SENSE_DATA)
rc = NDMSCSI_MAX_SENSE_DATA;
req->n_sense_data = rc;
NDMOS_API_BCOPY (reply->ext_sense.ext_sense_val,
req->sense_data, rc);
}
switch (req->data_dir) {
case NDMSCSI_DD_IN:
req->n_data_done = reply->datain.datain_len;
if (req->n_data_done > 0) {
NDMOS_API_BCOPY (reply->datain.datain_val,
req->data, req->n_data_done);
}
break;
case NDMSCSI_DD_OUT:
req->n_data_done = reply->dataout_len;
break;
}
req->completion_status = NDMSCSI_CS_GOOD;
NDMC_FREE_REPLY();
NDMC_ENDWITH
return 0;
}