Merge branch 'master' into squeeze
[debian/amanda] / ndmp-src / ndml_scsi.c
diff --git a/ndmp-src/ndml_scsi.c b/ndmp-src/ndml_scsi.c
new file mode 100644 (file)
index 0000000..7e65365
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * 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;
+}