OpenSolaris_b135/cmd/mms/mm/common/mm_mmp_mount.c

Compare this file to the similar file:
Show the results in this format:

/*
 * 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
 * or http://www.opensolaris.org/os/licensing.
 * 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 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <syslog.h>
#include <mms_list.h>
#include <mms_parser.h>
#include <mms_par_impl.h>
#include <libpq-fe.h>
#include <mms_trace.h>
#include <mms_strapp.h>
#include "mm_db.h"
#include "mm.h"
#include "mm_util.h"
#include "mm_commands.h"
#include "mm_sql.h"
#include "mm_sql_impl.h"
#include "mm_task.h"
#include "mm_path.h"

static char *_SrcFile = __FILE__;

#define	SELECT_GETALL "select \"DriveName\" from "	\
	"getall('%s', '%s', '%s');"

#define	SELECT_LIB "select \"LibraryName\" from "	\
	"gettypename('%s', '%s');"

/* Unmount command states */
#define	UM_CANDIDATE_SELECTION 0
#define	UM_DM_DETACH 1
#define	UM_SCHEDULE_UNLOAD 2
#define	UM_DM_UNLOAD 3
#define	UM_DM_RELEASE 4
#define	UM_LM_UNMOUNT 5
#define	UM_FINAL 100

extern int mm_get_dest(mm_wka_t *mm_wka, mm_command_t *cmd);
extern int mm_get_source(mm_wka_t *mm_wka, mm_command_t *cmd);
extern int mm_get_const(mm_wka_t *mm_wka, mm_command_t *cmd);
extern int mm_add_match_list(char *str, mms_list_t *list);
extern void tm_be_cancel_all(mm_command_t *cmd);

void
mm_print_unmount_state(int state) {
	switch (state) {
	case UM_CANDIDATE_SELECTION:
		mms_trace(MMS_DEBUG,
		    "unmount candidate selection");
		return;
	case UM_DM_DETACH:
		mms_trace(MMS_DEBUG,
		    "add dm detach command");
		return;
	case UM_SCHEDULE_UNLOAD:
		mms_trace(MMS_DEBUG,
		    "schedule dm unload command");
		return;
	case UM_DM_UNLOAD:
		mms_trace(MMS_DEBUG,
		    "add dm unload command");
		return;
	case UM_DM_RELEASE:
		mms_trace(MMS_DEBUG,
		    "add dm release command");
		return;

	case UM_LM_UNMOUNT:
		mms_trace(MMS_DEBUG,
		    "add lm unmount command");
		return;

	case UM_FINAL:
		mms_trace(MMS_DEBUG,
		    "umount final commmand state");
		return;

	}
}

void
mm_print_mount_candidates(mm_command_t *cmd) {
	cmd_mount_info_t	*mount_info = &cmd->cmd_mount_info;
	cmi_cart_list_t		*cart = NULL;
	cmi_drive_list_t	*drive = NULL;

	mms_trace(MMS_INFO, "Candidate Cartridges are :");
	mms_list_foreach(&mount_info->cmi_cart_list, cart) {
		if (cart->cmi_cart_not_ready) {
			mms_trace(MMS_INFO, "    Cartridge, %s, (not ready)",
			    cart->cmi_cart_id);
		} else {
			mms_trace(MMS_INFO, "    Cartridge, %s",
			    cart->cmi_cart_id);
		}
		if (cart->cmi_cart_pcl != NULL) {
			mms_trace(MMS_INFO, "      %s",
			    cart->cmi_cart_pcl);
		}
		mms_trace(MMS_INFO, "     Library, %s",
		    cart->cmi_library);
		mms_trace(MMS_INFO,
		    "     Drive Candidates:");
		mms_list_foreach(&cart->cmi_drive_list, drive) {
			if (drive->cmi_mode_valid == 0) {
				mms_trace(MMS_INFO, "        %s"
				    "  * no DM configured *",
				    drive->cmi_drive_name);
			} else {
				if (drive->cmi_drive_not_ready) {
					mms_trace(MMS_INFO,
					    "        %s, (not ready)",
					    drive->cmi_drive_name);
				} else {
					mms_trace(MMS_INFO, "        %s",
					    drive->cmi_drive_name);
				}
			}
		}
	}
}
void
mm_print_accessmodes(mm_command_t *cmd) {
	cmd_mount_info_t	*mount_info = &cmd->cmd_mount_info;
	cmi_mode_list_t		*mode = NULL;
	int			i;

	mms_trace(MMS_INFO, "Number of First Mount Tokens's is %d",
	    mount_info->cmi_num_firstmount);

	for (i = 0; i < mount_info->cmi_num_firstmount; i ++) {
		mms_trace(MMS_INFO, "  First Mount Token %d is %s", i,
		    mount_info->cmi_firstmount[i]);
	}
	mms_trace(MMS_INFO, "Total Number of Access Modes is %d",
	    mount_info->cmi_total_modes);
	mms_list_foreach(&mount_info->cmi_mode_list, mode) {
		for (i = 0;
		    i < mode->cmi_num_accessmode;
		    i ++) {
			mms_trace(MMS_INFO, "  Mode Token %d is %s", i,
			    mode->cmi_accessmode[i]);
		}
	}
}
void
mm_print_mount_summary(mm_wka_t *mm_wka, mm_command_t *cmd) {

	cmd_mount_info_t	*mount_info = &cmd->cmd_mount_info;
	cci_t			*conn = &mm_wka->wka_conn;

	/* Print mount information */
	if (mount_info->cmi_operation == MM_MOUNT) {
		mms_trace(MMS_INFO, "*** Mount Summary ***");
	} else {
		mms_trace(MMS_INFO, "*** UnMount Summary ***");
	}
	mms_trace(MMS_INFO, "Application is %s",
	    conn->cci_client);
	mms_trace(MMS_INFO, "Instance is %s",
	    conn->cci_instance);
	if (cmd->wka_ptr->wka_privilege == MM_PRIV_STANDARD) {
		mms_trace(MMS_INFO,
		    "Standard Privilege");
	} else {
		mms_trace(MMS_INFO,
		    "Privileged Client");
	}
	switch (mount_info->cmi_type) {
	case MM_SIDE:
		mms_trace(MMS_INFO, "    Type is SIDE");
		break;
	case MM_PARTITION:
		mms_trace(MMS_INFO, "    Type is PARTITION");
		break;
	case MM_VOLUME:
		mms_trace(MMS_INFO, "    Type is VOLUME");
		break;
	}
	switch (mount_info->cmi_when) {
	case MM_BLOCKING:
		mms_trace(MMS_INFO, "    When is 'blocking'");
		break;
	case MM_IMMEDIATE:
		mms_trace(MMS_INFO, "    When is 'immediate'");
		break;
	}

	if (mount_info->cmi_where)
		mms_trace(MMS_INFO,
		    "    Where is %s", mount_info->cmi_where);


	/* Print access modes */
	if (mount_info->cmi_operation == MM_MOUNT)
		mm_print_accessmodes(cmd);

	/* Print all the cartridge/library/drive information */
	mm_print_mount_candidates(cmd);
}

int
mm_check_drive(mm_wka_t *mm_wka, mm_command_t *cmd,
    cmi_drive_list_t *drive_struct,
    char *cart_id, char *dm_name, mm_db_t *db)
{
	/* Need to set cmd error buf for every return (0) */
	cmd_mount_info_t	*mount_info = &cmd->cmd_mount_info;
	cmi_mode_list_t		*mode;

	char			*cap_tokens = NULL;
	int			a_mode = 0;
	char			*drive = drive_struct->cmi_drive_name;

	/* Check if a DM is configured for this drive */
	if (mm_db_exec(HERE, db, "select * from \"DMCAPABILITYGROUP\" "
	    "where \"DriveName\" = '%s';", drive) != MM_DB_DATA) {
		mms_trace(MMS_ERR, "Error getting DMCAPABILITYGROUP");
		mm_sql_db_err_rsp_new(cmd, db);
		return (0);
	}
	if (PQntuples(db->mm_db_results) == 0) {
		/* DM is not configured for this drive */
		mm_response_error(cmd,
		    ECLASS_CONFIG,
		    "EDRVNODMCONFIGURED",
		    MM_5035_MSG,
		    "dm",
		    dm_name,
		    "drive",
		    drive,
		    NULL);
		mm_clear_db(&db->mm_db_results);
		return (0);
	}
	mm_clear_db(&db->mm_db_results);

	/* Check the cartridge shape */
	if (mm_db_exec(HERE, db,
	    "select distinct * from drive_cart('%s', '%s');",
	    drive, cart_id) != MM_DB_DATA) {
		mms_trace(MMS_ERR, "Error checking drive shape");
		mm_sql_db_err_rsp_new(cmd, db);
		return (0);
	}
	if (PQntuples(db->mm_db_results) == 0) {
		/* Drive does not support this cartridge shape */
		mms_trace(MMS_DEVP, "Drive does not support "\
		    "this cartridge shape, %s %s", drive, cart_id);
		mm_response_error(cmd,
		    ECLASS_COMPAT,
		    "ECARTDRVNOTCOMPATIBLE",
		    MM_5096_MSG,
		    "drive",
		    drive,
		    "cart",
		    cart_id,
		    NULL);
		mm_clear_db(&db->mm_db_results);
		return (0);
	}
	mm_clear_db(&db->mm_db_results);

	/* For each Access Mode, check if the drive supports it */
	mms_list_foreach(&mount_info->cmi_mode_list, mode) {
		mms_trace(MMS_DEVP,
		    "checking a mode");
		a_mode = 1;
		cap_tokens = (char *)mm_check_mode(mm_wka,
		    cmd, drive, mode,
		    cart_id, db);
		if (cap_tokens != NULL) {
			/* There is at least one supported mode */
			mms_trace(MMS_DEVP, "Good mode is %s",
			    cap_tokens);
			/* mode is ok */
			free(cap_tokens);
			return (1);
		}
	}
	if (a_mode) {
		/* there was at least 1 mode passed, */
		/* and none were not good, return error */
		if (cap_tokens != NULL) {
			free(cap_tokens);
		}
		mm_response_error(cmd,
		    ECLASS_COMPAT,
		    "ECARTDRVNOTCOMPATIBLE",
		    MM_5036_MSG,
		    "dm",
		    dm_name,
		    "drive",
		    drive,
		    NULL);
		return (0);
	}
	/* No modes exist, access is default */
	if (cap_tokens != NULL) {
		free(cap_tokens);
	}
	return (1);

no_mem:
	MM_ABORT_NO_MEM();
	return (MM_CMD_ERROR);
}

#ifdef	MM_LIBRARY_DRIVE_HAS_PCL
static int
mm_library_drive_has_pcl(mm_command_t *cmd, char *library, char *drive,
    char *cart_pcl)
{
	mm_db_t		*db = &cmd->wka_ptr->mm_data->mm_db;
	int		 loaded;

	if (mm_db_exec(HERE, db, "select \"DriveName\" from \"DRIVE\" "
	    "where \"LibraryName\" = '%s' "
	    "and \"DriveName\" = '%s' "
	    "and \"CartridgePCL\" = '%s' "
	    "and \"DriveLibraryAccessible\" = 'true' "
	    "and \"DriveLibraryOccupied\" = 'true' "
	    "and \"DriveBroken\" = 'false' "
	    "and \"DriveDisabled\" = 'false';",
	    library, drive, cart_pcl) != MM_DB_DATA) {
		return (0);
	}
	loaded = (PQntuples(db->mm_db_results) != 1 ? 0 : 1);
	mm_clear_db(&db->mm_db_results);
	return (loaded);
}
#endif
int
mm_candidate_drive_ok(mm_wka_t *mm_wka,
    mm_command_t *cmd, mm_db_t *db,
    char *candidate_cartid,
    cmi_drive_list_t *drive) {

	/* Determines if the candidate drive */
	/* is available as a candidate */
	char			*candidate_drive = drive->cmi_drive_name;
	char			*candidate_dm = drive->cmi_dm_name;

	cci_t			*conn = &mm_wka->wka_conn;
	cmd_mount_info_t	*mount_info = &cmd->cmd_mount_info;

	mm_dm_stat_t		*dm_stat = NULL;
	mm_drive_stat_t		*drive_stat = NULL;

	int			rc;
	mms_trace(MMS_DEVP, "mm_candidate_drive_ok");
	if ((drive_stat = mm_get_drive_status(candidate_drive, db)) == NULL) {
		mms_trace(MMS_ERR,
		    "Error getting drive information, "
		    "drive %s",
		    candidate_drive);
		mm_system_error(cmd,
		    "failed to get drive information");
		rc = 0; goto end;
	}

	/* For mounts we know drive and host, for umounts we know dm */
	/* Use the approperate call to getdmstatus */
	if (mount_info->cmi_operation == MM_MOUNT) {
		if ((dm_stat = mm_get_dm_status(NULL, candidate_drive,
		    mount_info->cmi_where, db)) == NULL) {
			mms_trace(MMS_ERR,
			    "Error getting dm information, "
			    "drive %s",
			    candidate_drive);
			mm_system_error(cmd,
			    "failed to get dm information");
			rc = 0; goto end;
		}
	} else {
		mms_trace(MMS_DEVP,
		    "cmi_dm_name/candidate_dm == %s",
		    candidate_dm);
		if ((dm_stat = mm_get_dm_status(candidate_dm, NULL,
		    NULL, db)) == NULL) {
			mms_trace(MMS_ERR,
			    "Error getting dm information, "
			    "drive %s",
			    candidate_drive);
			mm_system_error(cmd,
			    "failed to get dm information");
			rc = 0; goto end;
		}
	}

	mm_print_drive_status(drive_stat);


	mm_print_dm_status(dm_stat);

	/* The order of check is the order errors get returned */
	/* check higher level problems before lower level */
	/* ie. online, diabled first */

	/* Exclusive access check */
	if (strcmp(drive_stat->drive_stat_excl_app, "none") != 0) {
		if (strcmp(conn->cci_client,
		    drive_stat->drive_stat_excl_app) != 0) {
			mms_trace(MMS_DEVP,
			    "%s exclusive app is not clients app,"
			    " ExclusiveAppName != %s or none",
			    candidate_drive,
			    conn->cci_client);
			mm_response_error(cmd,
			    ECLASS_EXPLICIT,
			    "EAPPDRVNOACC",
			    MM_5027_MSG,
			    "app", conn->cci_client,
			    "drive", candidate_drive,
			    NULL);
			rc = 0; goto end;
		}
	}

	/* DRIVEGROUPAPPLICATION check */
	if (cmd->wka_ptr->wka_privilege == MM_PRIV_STANDARD) {
		mms_trace(MMS_DEVP,
		    "Non-privileged client, "
		    "checking Drive Access");
		/* standard priv, check drive group access */
		if (mm_db_exec(HERE, db,
		    "select \"DRIVEGROUPAPPLICATION\".\"ApplicationName\" "
		    "from \"DRIVEGROUPAPPLICATION\" "
		    "where \"DriveGroupName\" = '%s' and "
		    "\"ApplicationName\" = '%s';",
		    drive_stat->drive_stat_group,
		    conn->cci_client) != MM_DB_DATA) {
			mms_trace(MMS_ERR,
			    "Error getting drive group information, "
			    "drive %s, db trans failed",
			    candidate_drive);
			mm_sql_db_err_rsp_new(cmd, db);
			rc = 0; goto end;
		}
		if (PQntuples(db->mm_db_results) == 0) {
			mms_trace(MMS_DEVP,
			    "%s does not have "
			    "access to drive group %s",
			    conn->cci_client,
			    drive_stat->drive_stat_group);
			mm_response_error(cmd,
			    ECLASS_EXPLICIT,
			    "EAPPDRVNOACC",
			    MM_5030_MSG,
			    "app", conn->cci_client,
			    "drive", candidate_drive,
			    NULL);
			mm_clear_db(&db->mm_db_results);
			rc = 0; goto end;
		}
		mm_clear_db(&db->mm_db_results);
	} else {
		mms_trace(MMS_DEVP,
		    "Privileged Client, "
		    "skip Drive Access check");
	}


	/* Online check */
	if ((strcmp(drive_stat->drive_stat_online, "false") == 0) ||
	    (strcmp(drive_stat->drive_stat_online, "f") == 0)) {
		mms_trace(MMS_DEVP,
		    "%s is not online",
		    candidate_drive);
		mm_response_error(cmd,
		    ECLASS_PERMPRIV,
		    "EDRIVEOFFLINE",
		    MM_5029_MSG,
		    "drive", candidate_drive,
		    NULL);
		rc = 0; goto end;
	}

	/* Drive In use */
	if ((mount_info->cmi_operation == MM_MOUNT) &&
	    (strcmp(drive_stat->drive_stat_soft, "ready") != 0)) {
		mms_trace(MMS_DEVP,
		    "%s is not ready,"
		    " DriveStateSoft != ready ",
		    candidate_drive);
		drive->cmi_drive_not_ready = 1;
		mm_response_error(cmd,
		    ECLASS_RETRY,
		    "EDRVINUSE",
		    MM_5025_MSG,
		    "drive", candidate_drive,
		    NULL);
		mm_set_retry_drive(cmd,
		    candidate_drive);
		if (mount_info->cmi_when == MM_IMMEDIATE) {
			rc = 0; goto end;
		} else {
			mms_trace(MMS_DEVP,
			    "drive in use, keep as"
			    " candidate for blocking mounts");
			mm_response_error(cmd,
			    ECLASS_RETRY,
			    "EDRVINUSE",
			    MM_5025_MSG,
			    "drive", candidate_drive,
			    NULL);
			mm_set_retry_drive(cmd,
			    candidate_drive);
		}
		/* Keep this drive as a candidate for blocking mounts */

	}

	if ((mount_info->cmi_operation == MM_MOUNT) &&
	    ((strcmp(drive_stat->drive_stat_hard, "loaded") == 0) ||
	    (strcmp(drive_stat->drive_stat_drvlib_occ, "true") == 0) ||
	    (strcmp(drive_stat->drive_stat_drvlib_occ, "t") == 0))) {
		/* Find this drive's delayed unload and set to dispatch */
		mms_trace(MMS_DEVP,
		    "drive is loaded with %s, need to unload",
		    drive_stat->drive_stat_pcl);

		if ((strcmp(drive_stat->drive_stat_hard, "unloading") == 0) ||
		    (strcmp(drive_stat->drive_stat_hard, "loading") == 0)) {
			/* This drive is in the process of unloading */
			mms_trace(MMS_DEVP,
			    "This drive is in the process of "
			    "unloading/loading");
			drive->cmi_drive_not_ready = 1;
			mm_response_error(cmd,
			    ECLASS_RETRY,
			    "EDRVUNLOADING",
			    MM_5102_MSG,
			    "drive", candidate_drive,
			    NULL);
			mm_set_retry_drive(cmd,
			    candidate_drive);
			if (mount_info->cmi_when == MM_IMMEDIATE) {
				rc = 0; goto end;
			}
		} else {
			drive->cmi_drive_loaded = 1;
			drive->cmi_loaded_pcl = NULL;
			drive->cmi_loaded_pcl = mms_strapp(drive->
			    cmi_loaded_pcl,
			    drive_stat->drive_stat_pcl);
			if (strcmp(MM_NON_MMS_CART,
			    drive_stat->drive_stat_pcl) == 0) {
				drive->cmi_drive_not_ready = 1;
				mms_trace(MMS_DEVP,
				    "drive is loaded with a non-mms tape");
				mm_response_error(cmd,
				    ECLASS_RETRY,
				    "EDRVINUSE",
				    MM_5028_MSG,
				    "drive", candidate_drive,
				    NULL);
				mm_set_retry_drive(cmd,
				    candidate_drive);
				if (mount_info->cmi_when == MM_IMMEDIATE) {
					rc = 0; goto end;
				}
			}
		}
	}

	if (mount_info->cmi_operation == MM_UNMOUNT) {
		if ((strcmp(drive_stat->drive_stat_hard, "loaded") != 0) ||
		    (strcmp(drive_stat->drive_stat_drvlib_occ, "t") != 0)) {
			mms_trace(MMS_DEVP,
			    "%s not loaded/occupied with tape, "
			    "but has MOUNTPHYSICAL",
			    candidate_drive);
			mm_system_error(cmd,
			    "drive with MOUNTPHYSICAL not "
			    "loaded/occupied with tape");
			rc = 0; goto end;
		}
	}


	/* Drive disabled */
	if ((strcmp(drive_stat->drive_stat_disabled, "true") == 0) ||
	    (strcmp(drive_stat->drive_stat_disabled, "t") == 0)) {
		mms_trace(MMS_DEVP,
		    "%s is disabled",
		    candidate_drive);
		if (strcmp(drive_stat->drive_stat_disabled,
		    "temporary") == 0) {
			mm_response_error(cmd,
			    ECLASS_PERMPRIV,
			    "EDRVDISABLEDTEMP",
			    MM_5022_MSG,
			    "drive", candidate_drive,
			    NULL);

		} else {
			mm_response_error(cmd,
			    ECLASS_PERMPRIV,
			    "EDRVDISABLEDPERM",
			    MM_5023_MSG,
			    "drive", candidate_drive,
			    NULL);
		}
		rc = 0; goto end;
	}
	/* Drive Broken */
	if ((strcmp(drive_stat->drive_stat_broken, "true") == 0) ||
	    (strcmp(drive_stat->drive_stat_broken, "t") == 0)) {
		mms_trace(MMS_DEVP,
		    "%s is broken",
		    candidate_drive);
		mm_response_error(cmd,
		    ECLASS_CONFIG,
		    "EDRVBROKEN",
		    MM_5024_MSG,
		    "drive", candidate_drive,
		    NULL);
		rc = 0; goto end;
	}

	/* Drive is library accessible */
	if ((strcmp(drive_stat->drive_stat_lib_acc, "false") == 0) ||
	    (strcmp(drive_stat->drive_stat_lib_acc, "f") == 0)) {
		mms_trace(MMS_DEVP,
		    "%s is not accessible",
		    candidate_drive);
		mm_response_error(cmd,
		    ECLASS_INTERNAL,
		    "ELMDRVNOTACCESS",
		    MM_5026_MSG,
		    "drive", candidate_drive,
		    NULL);
		rc = 0; goto end;
	}

	/* DM Status Checks */
	if (strcmp(dm_stat->dm_stat_soft, "ready") != 0) {
		mms_trace(MMS_DEVP,
		    "DM for %s is not ready,"
		    " DMStateSoft != ready ",
		    candidate_drive);

		if (strcmp(dm_stat->dm_stat_soft,
		    "absent") == 0) {
			mm_response_error(cmd,
			    ECLASS_RETRY,
			    "EDMNOTCONNECTED",
			    MM_5032_MSG,
			    "dm",
			    dm_stat->dm_stat_name,
			    "drive",
			    candidate_drive,
			    NULL);
			rc = 0; goto end;
		} else if (strcmp(dm_stat->dm_stat_soft,
		    "disconnected") == 0) {
			mm_response_error(cmd,
			    ECLASS_CONFIG,
			    "EDRVBROKEN",
			    MM_5033_MSG,
			    "dm",
			    dm_stat->dm_stat_name,
			    "drive",
			    candidate_drive,
			    NULL);
			mm_set_retry_drive(cmd,
			    candidate_drive);
			rc = 0; goto end;
		} else if (strcmp(dm_stat->dm_stat_soft,
		    "not ready") == 0) {
			/* drive is not ready for blocked */
			drive->cmi_drive_not_ready = 1;
			mm_response_error(cmd,
			    ECLASS_RETRY,
			    "EDMSTILLBOOTING",
			    MM_5034_MSG,
			    "dm",
			    dm_stat->dm_stat_name,
			    "drive",
			    candidate_drive,
			    NULL);
			if (mount_info->cmi_when == MM_IMMEDIATE) {
				rc = 0; goto end;
			}
		} else if (strcmp(dm_stat->dm_stat_soft,
		    "present") == 0) {
			/* drive is not ready for blocked */
			drive->cmi_drive_not_ready = 1;
				mm_response_error(cmd,
				    ECLASS_CONFIG,
				    "EDRVNODMCONFIGURED",
				    MM_5034_MSG,
				    "dm",
				    dm_stat->dm_stat_name,
				    "drive",
				    candidate_drive,
				    NULL);
				mm_set_retry_drive(cmd,
				    candidate_drive);
			if (mount_info->cmi_when == MM_IMMEDIATE) {
				rc = 0; goto end;
			}
		} else if ((mount_info->cmi_operation == MM_MOUNT) &&
		    (strcmp(dm_stat->dm_stat_soft,
		    "reserved") == 0)) {
			/* drive is not ready for blocked */
			drive->cmi_drive_not_ready = 1;
			mm_response_error(cmd,
			    ECLASS_RETRY,
			    "EDRVINUSE",
			    MM_5098_MSG,
			    "dm",
			    dm_stat->dm_stat_name,
			    NULL);
			mm_set_retry_drive(cmd,
			    candidate_drive);
			if (mount_info->cmi_when == MM_IMMEDIATE) {
				rc = 0; goto end;
			}
		}
	} else if (mount_info->cmi_operation == MM_UNMOUNT) {
		/* Unmount, and DM is ready */
		mms_trace(MMS_DEVP,
		    "%s is in incorrect state for unmount",
		    dm_stat->dm_stat_name);
		mm_system_error(cmd,
		    "DM is in incorrect state for unmount");
		rc = 0; goto end;
	}

	if (strcmp(dm_stat->dm_stat_hard, "ready") != 0) {
		mms_trace(MMS_DEVP,
		    "DM for %s is not ready,"
		    " DMStateHard != ready ",
		    candidate_drive);
		mm_response_error(cmd,
		    ECLASS_CONFIG,
		    "EDRVBROKEN",
		    MM_5031_MSG,
		    "drive",
		    candidate_drive,
		    "dm",
		    dm_stat->dm_stat_name,
		    NULL);
		rc = 0; goto end;
	}
	if (mount_info->cmi_operation == MM_UNMOUNT) {
		mms_trace(MMS_DEVP,
		    "Drive/DM Status ok for unmounts");
		rc = 1; goto end;
	}


	mms_trace(MMS_DEVP,
	    "DM Status ok, check DM accessmodes DM, %s",
	    dm_stat->dm_stat_name);

	if (mm_check_drive(mm_wka, cmd,
	    drive,
	    candidate_cartid,
	    dm_stat->dm_stat_name,
	    db) == 1) {
		/* DM supports the access modes */
		mms_trace(MMS_DEVP,
		    "DM configured for at least 1 access mode");
	} else {
		mms_trace(MMS_DEVP,
		    "DM not configured to support the access mode");
		/* Error buf should be set by check drive */
		rc = 0; goto end;
	}


	rc = 1; goto end;

end:
	mm_free_drive_status(drive_stat);
	mm_free_dm_status(dm_stat);
	return (rc);
}

int
mm_candidate_cartridge_ok(mm_wka_t *mm_wka,
    mm_command_t *cmd, mm_db_t *db,
    cmi_cart_list_t *cart_struct) {

	uuid_text_t		*candidate_cartid = &cart_struct->cmi_cart_id;

	cci_t			*conn = &mm_wka->wka_conn;
	cmd_mount_info_t	*mount_info = &cmd->cmd_mount_info;

	PGresult		*cart = NULL;
	PGresult		*volume = NULL;
	PGresult		*slot = NULL;

	int			rc;
	mms_trace(MMS_DEVP, "mm_candidate_cartridge_ok");
	if (mm_db_exec(HERE, db,
	    "select "
	    "\"CARTRIDGE\".\"CartridgeState\", "
	    "\"CARTRIDGE\".\"CartridgeStatus\", "
	    "\"CARTRIDGE\".\"CartridgeGroupName\", "
	    "\"CARTRIDGE\".\"CartridgeDriveOccupied\" "
	    "from \"CARTRIDGE\" "
	    "where \"CartridgeID\" = '%s';",
	    candidate_cartid) != MM_DB_DATA) {
		mms_trace(MMS_ERR,
		    "Error getting cartridge information, "
		    "cartridge, %s, db trans failed",
		    candidate_cartid);
		mm_sql_db_err_rsp_new(cmd, db);
		rc = 0; goto end;
	}
	cart = db->mm_db_results;
	if (PQntuples(cart) != 1) {
		mms_trace(MMS_ERR,
		    "Error getting cartridge information, "
		    "cartridge, %s, db results != 1",
		    candidate_cartid);
		mm_system_error(cmd,
		    "row number mismatch getting "
		    "cartridge information");
		rc = 0; goto end;
	}
	mms_trace(MMS_DEVP,
	    "Cartridge Status for Cartridge, %s",
	    candidate_cartid);
	mms_trace(MMS_DEVP,
	    "    CartridgeState = %s",
	    PQgetvalue(cart, 0, 0));
	mms_trace(MMS_DEVP,
	    "    CartridgeStatus = %s",
	    PQgetvalue(cart, 0, 1));
	mms_trace(MMS_DEVP,
	    "    CartridgeGroup = %s",
	    PQgetvalue(cart, 0, 2));
	mms_trace(MMS_DEVP,
	    "    CartridgeDriveOccupied = %s",
	    PQgetvalue(cart, 0, 3));

	/* Ignore this attribute for now */
	/*
	 * if (strcmp(PQgetvalue(cart, 0, 0), "defined") != 0) {
	 *
	 * }
	 */

	if ((mount_info->cmi_operation == MM_MOUNT) &&
	    (strcmp(PQgetvalue(cart, 0, 1), "available") != 0)) {
		mms_trace(MMS_DEVP,
		    "%s is in use,"
		    " CartridgeStatus != available ",
		    candidate_cartid);
		if (strcmp(PQgetvalue(cart, 0, 1),
		    "unavailable") == 0) {
			mm_response_error(cmd,
			    ECLASS_CONFIG,
			    "ECARTNOTLOCATED",
			    MM_5037_MSG,
			    "cart",
			    candidate_cartid,
			    NULL);
			rc = 0; goto end;
		}
		/* mark this cartridge not ready */
		/* for blocked mounts */
		cart_struct->cmi_cart_not_ready = 1;
		/* State is 'in use' */
		mm_response_error(cmd,
		    ECLASS_RETRY,
		    "ECARTINUSE",
		    MM_5038_MSG,
		    "cart",
		    candidate_cartid,
		    NULL);
		mm_set_retry_cart(cmd,
		    (char *)candidate_cartid);
		if (mount_info->cmi_when == MM_IMMEDIATE) {
			rc = 0; goto end;
		}
	}
	if ((mount_info->cmi_operation == MM_UNMOUNT) &&
	    (strcmp(PQgetvalue(cart, 0, 1), "in use") != 0)) {
		mms_trace(MMS_DEVP,
		    "%s is not in use,"
		    " CartridgeStatus != in use ",
		    candidate_cartid);
		mm_system_error(cmd,
		    "cartridge status is not in use");
		rc = 0; goto end;
	}

	/* Check if this CARTRIDGE has a SLOT created for it */
	if (mm_db_exec(HERE, db,
	    "select \"SlotName\" "
	    "from \"SLOT\" "
	    "where \"CartridgeID\" = '%s';",
	    candidate_cartid) != MM_DB_DATA) {
		mms_trace(MMS_ERR,
		    "Error getting slot info, "
		    "cartridge, %s, db trans failed",
		    candidate_cartid);
		mm_sql_db_err_rsp_new(cmd, db);
		rc = 0; goto end;
	}
	slot = db->mm_db_results;
	if (PQntuples(slot) == 0) {
		mms_trace(MMS_DEVP,
		    "no slot found for cartridge, %s",
		    candidate_cartid);
		mm_response_error(cmd,
		    ECLASS_CONFIG,
		    "ENOSLOT",
		    MM_5095_MSG,
		    "cart",
		    candidate_cartid,
		    NULL);
		rc = 0; goto end;
	}


	if (mount_info->cmi_operation == MM_UNMOUNT) {
		/* skip volume check */
		/* This cart already has mapped to mount physical */
		mms_trace(MMS_DEVP,
		    "skip vol check for unmount");
		rc = 1; goto end;
	}


	/* Get VOLUME information */
	mms_trace(MMS_DEVP,
	    "Checking for Volumes");
	if (mm_db_exec(HERE, db,
	    "select \"ApplicationName\" "
	    "from \"VOLUME\" where "
	    "\"CartridgeID\" = '%s' and "
	    "\"ApplicationName\" = '%s';",
	    candidate_cartid,
	    conn->cci_client) != MM_DB_DATA) {
		mms_trace(MMS_ERR,
		    "Error getting volume information, "
		    "cartridge, %s, db trans failed",
		    candidate_cartid);
		mm_sql_db_err_rsp_new(cmd, db);
		rc = 0; goto end;
	}
	volume = db->mm_db_results;
	if (PQntuples(volume) == 0) {
		mms_trace(MMS_DEVP,
		    "%s doesn't have a volume "
		    "on cartridge, %s",
		    conn->cci_client,
		    candidate_cartid);
		mm_response_error(cmd,
		    ECLASS_CONFIG,
		    "EAPPHASNOVOLS",
		    MM_5040_MSG,
		    "app",
		    conn->cci_client,
		    "cart",
		    candidate_cartid,
		    NULL);
		rc = 0; goto end;
	}


	rc = 1; goto end;

end:
	if (cart != NULL) {
		mm_clear_db(&cart);
	}
	if (volume != NULL) {
		mm_clear_db(&volume);
	}
	if (slot != NULL) {
		mm_clear_db(&slot);
	}
	return (rc);

}


int
mm_candidate_library_ok(mm_command_t *cmd, mm_db_t *db,
    char *candidate_library) {

	/* Determines if the candidate library */
	/* is available as a candidate */

	mm_lm_stat_t		*lm_stat = NULL;
	mm_lib_stat_t		*lib_stat = NULL;

	int			rc;
	mms_trace(MMS_DEVP, "mm_candidate_library_ok");
	if ((lib_stat = mm_get_library_status(candidate_library, db)) == NULL) {
		mms_trace(MMS_ERR,
		    "Error getting library information, "
		    "library %s",
		    candidate_library);
		mm_system_error(cmd,
		    "failed to get library "
		    "information from database");
		rc = 0; goto end;
	}

	mm_print_library_status(lib_stat);

	if ((strcmp(lib_stat->lib_stat_online, "false") == 0) ||
	    (strcmp(lib_stat->lib_stat_online, "f") == 0)) {
		mms_trace(MMS_DEVP,
		    "%s is not online",
		    candidate_library);
		mm_response_error(cmd,
		    ECLASS_PERMPRIV,
		    "ELIBRARYOFFLINE",
		    MM_5041_MSG,
		    "lib",
		    candidate_library,
		    NULL);
		rc = 0; goto end;
	}
	if ((strcmp(lib_stat->lib_stat_disabled, "true") == 0) ||
	    (strcmp(lib_stat->lib_stat_disabled, "t") == 0)) {
		mms_trace(MMS_DEVP,
		    "%s is disabled",
		    candidate_library);
		if (strcmp(lib_stat->lib_stat_disabled,
		    "temporary") == 0) {
			mm_response_error(cmd,
			    ECLASS_PERMPRIV,
			    "ELIBDISABLEDTEMP",
			    MM_5042_MSG,
			    "lib",
			    candidate_library,
			    NULL);
		} else {
			mm_response_error(cmd,
			    ECLASS_PERMPRIV,
			    "ELIBDISABLEDPERM",
			    MM_5043_MSG,
			    "lib",
			    candidate_library,
			    NULL);
		}
		rc = 0; goto end;
	}
	if ((strcmp(lib_stat->lib_stat_broken, "true") == 0) ||
	    (strcmp(lib_stat->lib_stat_broken, "t") == 0)) {
		mms_trace(MMS_DEVP,
		    "%s is broken",
		    candidate_library);
		mm_response_error(cmd,
		    ECLASS_CONFIG,
		    "ELIBBROKEN",
		    MM_5044_MSG,
		    "lib",
		    candidate_library,
		    NULL);
		rc = 0; goto end;
	}
	mms_trace(MMS_DEVP,
	    "Library status ok, check LM");

	/* Library is online and ready, get LM status */

	if ((lm_stat = mm_get_lm_status(lib_stat->lib_stat_lm,
	    db)) == NULL) {
		mms_trace(MMS_ERR,
		    "Error getting lm information, "
		    "library %s",
		    candidate_library);
		mm_system_error(cmd,
		    "failed to get lm information");
		rc = 0; goto end;
	}

	mm_print_lm_status(lm_stat);

	if (strcmp(lm_stat->lm_stat_hard, "ready") != 0) {
		mms_trace(MMS_DEVP,
		    "%s is not ready,"
		    " LMStateHard != ready ",
		    lib_stat->lib_stat_lm);
		mm_response_error(cmd,
		    ECLASS_CONFIG,
		    "ELIBBROKEN",
		    MM_5045_MSG,
		    "lm",
		    lib_stat->lib_stat_lm,
		    NULL);
		rc = 0; goto end;
	}
	if (strcmp(lm_stat->lm_stat_soft, "ready") != 0) {
		mms_trace(MMS_DEVP,
		    "%s is not ready,"
		    " LMStateSoft != ready ",
		    lib_stat->lib_stat_lm);
		if (strcmp(lm_stat->lm_stat_soft,
		    "absent") == 0) {
			mm_response_error(cmd,
			    ECLASS_RETRY,
			    "ELMNOTCONNECTED",
			    MM_5046_MSG,
			    "lm",
			    lib_stat->lib_stat_lm,
			    "lib",
			    lib_stat->lib_stat_name,
			    NULL);
			mm_set_retry_lib(cmd,
			    candidate_library);
		}
		if (strcmp(lm_stat->lm_stat_soft,
		    "present") == 0) {
			mm_response_error(cmd,
			    ECLASS_RETRY,
			    "ELMNOTREADY",
			    MM_5047_MSG,
			    "lm",
			    lib_stat->lib_stat_lm,
			    "lib",
			    lib_stat->lib_stat_name,
			    NULL);
			mm_set_retry_lib(cmd,
			    candidate_library);
		}
		if (strcmp(lm_stat->lm_stat_soft,
		    "disconnected") == 0) {
			mm_response_error(cmd,
			    ECLASS_CONFIG,
			    "ELIBBROKEN",
			    MM_5048_MSG,
			    "lm",
			    lib_stat->lib_stat_lm,
			    "lib",
			    lib_stat->lib_stat_name,
			    NULL);

		}
		if (strcmp(lm_stat->lm_stat_soft,
		    "not ready") == 0) {
			mm_response_error(cmd,
			    ECLASS_RETRY,
			    "ELMSTILLBOOTING",
			    MM_5049_MSG,
			    "lm",
			    lib_stat->lib_stat_lm,
			    "lib",
			    lib_stat->lib_stat_name,
			    NULL);
			mm_set_retry_lib(cmd,
			    candidate_library);
		}
		rc = 0; goto end;
	}
	mms_trace(MMS_DEVP,
	    "LM status ok");

	rc = 1; goto end;

end:
	mm_free_library_status(lib_stat);
	mm_free_lm_status(lm_stat);
	return (rc);

}


int
mm_insert_next_drive(mms_list_t *drive_list, cmi_drive_list_t  *drive_struct) {

	/*
	 * This will insert the drive_struct into its
	 * proper place in drive_list
	 *
	 * the drives are inserted in order of drive_priority
	 * check the dm shape and dm density priority to
	 * arrange the drives within each drive priority group
	 */

	cmi_drive_list_t		*drive;
	cmi_drive_list_t		*next_drive;

	int				drv_priority;
	int				dm_shape_priority;
	int				dm_density_priority;

	int				cur_drv_priority;
	int				cur_shape_priority;
	int				cur_density_priority;

	int				next_drv_priority;

	int				a_drive = 0;

	drv_priority = drive_struct->cmi_drv_priority;
	dm_shape_priority = drive_struct->cmi_dm_shape_priority;
	dm_density_priority = drive_struct->cmi_dm_density_priority;

	for (drive = mms_list_head(drive_list);
	    drive != NULL;
	    drive = next_drive) {
		a_drive = 1;
		next_drive =
		    mms_list_next(drive_list,
		    drive);
		cur_drv_priority = drive->cmi_drv_priority;
		cur_shape_priority = drive->cmi_dm_shape_priority;
		cur_density_priority = drive->cmi_dm_density_priority;

		if (cur_drv_priority != drv_priority) {
			/* go to the next drive */
			continue;
		}
		if (cur_shape_priority > dm_shape_priority) {
			/* Insert before cur */
			mms_list_insert_before(drive_list, drive, drive_struct);
			return (0);
		}
		if ((cur_shape_priority == dm_shape_priority) &&
		    (cur_density_priority > dm_density_priority)) {
			/* Insert before cur */
			mms_list_insert_before(drive_list, drive, drive_struct);
			return (0);
		}
		if (next_drive == NULL) {
			mms_list_insert_after(drive_list, drive, drive_struct);
			return (0);
		}
		next_drv_priority = next_drive->cmi_drv_priority;
		if (next_drv_priority != drv_priority) {
			mms_list_insert_after(drive_list, drive, drive_struct);
			return (0);
		}
	}
	mms_list_insert_tail(drive_list,
	    drive_struct);
	return (a_drive);
}

cmi_drive_list_t *
mm_setup_drive_unmount(mm_command_t *cmd,
    mm_db_t *db,
    cmi_cart_list_t *cart,
    PGresult *drive_results,
    int drive_row) {

	cmi_drive_list_t	*drive = NULL;

	PGresult		*dm;
	char			*dm_name = NULL;

	char *candidate_drive = PQgetvalue(drive_results, drive_row, 0);

	mms_trace(MMS_DEVP, "mm_setup_drive_unmount");

	if (mm_db_exec(HERE, db,
	    "select \"DMName\""
	    " from \"DRIVE\" where "
	    "\"DriveName\" = '%s';",
	    candidate_drive) != MM_DB_DATA) {
		mms_trace(MMS_ERR,
		    "Error getting dm information");
		mm_sql_db_err_rsp_new(cmd, db);
		return (NULL);
	}
	if (PQntuples(db->mm_db_results) == 0) {
		mms_trace(MMS_ERR,
		    "Coudn't find DRIVE for "
		    "this drive, %s",
		    candidate_drive);
		mm_system_error(cmd,
		    "missing DRIVE obj during unmount");
		mm_clear_db(&db->mm_db_results);
		return (NULL);
	}
	dm = db->mm_db_results;
	dm_name = PQgetvalue(dm, 0, 0);

	drive = NULL;
	drive = (cmi_drive_list_t *)
	    calloc(1,
	    sizeof (cmi_drive_list_t));
	if (drive == NULL) {
		mms_trace(MMS_ERR,
		    "Unable to malloc"\
		    " cmi_drive_list: %s",
		    strerror(errno));
		mm_system_error(cmd,
		    "unable to allocate mem for drive stat");
		mm_clear_db(&dm);
		return (NULL);
	}
	drive->cmi_drive_name =
	    strdup(candidate_drive);
	drive->cmi_mode_valid = 1;
	drive->cmi_drive_not_ready = 0;
	drive->cmi_drive_used = 0;

	drive->cmi_dm_name = mms_strapp(drive->cmi_dm_name, dm_name);
	drive->cmi_dm_shape_priority = 0;
	drive->cmi_dm_density_priority = 0;
	/* Column references must match what is in mm_mount_init_candidates */
	drive->cmi_drv_priority = atoi(PQgetvalue(drive_results,
	    drive_row, 2));
	drive->cmi_drv_num_mounts = atoi(PQgetvalue(drive_results,
	    drive_row, 3));
	mms_list_insert_tail(&cart->cmi_drive_list,
	    drive);
	mm_clear_db(&dm);
	return (drive);


}

cmi_drive_list_t *
mm_setup_drive(mm_command_t *cmd,
    mm_db_t *db,
    cmi_cart_list_t *cart,
    PGresult *drive_results,
    int drive_row) {

	/* drive_results is created in mm_init_candidates */

	cmi_drive_list_t	*drive = NULL;
	cmd_mount_info_t	*mount_info = &cmd->cmd_mount_info;

	PGresult		*dm_shape;
	int			dm_shape_priority;
	int			dm_density_priority;
	PGresult		*dm;
	char			*dm_name = NULL;
	char			*cart_type = cart->cmi_cart_type;
	char			*bit_format = cart->cmi_bit_format;
	int			drive_not_ready;
	int			i;

	char			*candidate_drive = PQgetvalue(drive_results,
	    drive_row, 0);

	char			*cur_dm_shape;
	char			*cur_dm_shape_priority;
	char			*cur_dm_density;
	char			*cur_dm_density_priority;

	/* get the dm name */
	/* get name by host */
	if (mm_db_exec(HERE, db,
	    "select \"DMName\""
	    " from \"DM\" where "
	    "\"DriveName\" = '%s' "
	    "and pg_host_ident("
	    "\"DMTargetHost\") "
	    "= pg_host_ident('%s');",
	    candidate_drive,
	    mount_info->cmi_where) != MM_DB_DATA) {
		mms_trace(MMS_ERR,
		    "Error getting dm information");
		mm_sql_db_err_rsp_new(cmd, db);
		return (NULL);
	}
	if (PQntuples(db->mm_db_results) == 0) {
		mms_trace(MMS_ERR,
		    "No dm configured for "
		    "this drive, on host %s",
		    mount_info->cmi_where);
		mm_response_error(cmd,
		    ECLASS_COMPAT,
		    "EAPPDMDIFFHOSTS",
		    MM_5050_MSG,
		    "host",
		    mount_info->cmi_where,
		    NULL);
		mm_clear_db(&db->mm_db_results);
		return (NULL);
	}
	dm = db->mm_db_results;
	dm_name = PQgetvalue(dm, 0, 0);
	/* Check the cartridge shape */
	if (mm_db_exec(HERE, db,
	    "select \"DMSHAPEPRIORITY\".\"DMName\", "
	    "\"DMSHAPEPRIORITY\".\"DMShapeName\","
	    "\"DMSHAPEPRIORITY\".\"DMShapePriority\","
	    "\"DMDENSITYPRIORITY\".\"DMDensityName\","
	    "\"DMDENSITYPRIORITY\".\"DMDensityPriority\" from "
	    "\"DMSHAPEPRIORITY\",\"DMDENSITYPRIORITY\""
	    "where "
	    "\"DMSHAPEPRIORITY\".\"DMName\" = '%s' and "
	    "\"DMDENSITYPRIORITY\".\"DMName\" = '%s';",
	    dm_name,
	    dm_name) != MM_DB_DATA) {
		mms_trace(MMS_ERR,
		    "Error checking cartridge shape");
		mm_sql_db_err_rsp_new(cmd, db);
		mm_clear_db(&dm);
		return (NULL);
	}
	drive_not_ready = 0;
	if (PQntuples(db->mm_db_results) == 0) {
		/* This will be an error for immediate mounts */
		/* for blocking keep drive, and set drive_not_ready */
		mms_trace(MMS_ERR,
		    "dm has not been configured for this drive");
		drive_not_ready = 1;

	}
	dm_shape = db->mm_db_results;
	dm_shape_priority = -1;
	/* Default density is 1 */
	dm_density_priority = 1;

	for (i = 0; i < PQntuples(dm_shape); i++) {
		cur_dm_shape = PQgetvalue(dm_shape, i, 1);
		cur_dm_shape_priority = PQgetvalue(dm_shape, i, 2);
		cur_dm_density = PQgetvalue(dm_shape, i, 3);
		cur_dm_density_priority = PQgetvalue(dm_shape, i, 4);
		if (strcmp(cart_type, cur_dm_shape) == 0) {
			dm_shape_priority = atoi(cur_dm_shape_priority);
		}
		if (strcmp(bit_format, cur_dm_density) == 0) {
			dm_density_priority = atoi(cur_dm_density_priority);
		}
	}
	if ((dm_shape_priority == -1) &&
	    (drive_not_ready != 1)) {
		/* Drive has configed dm, but slot does not match */
		/* Didn't find this dm_shape */
		mms_trace(MMS_ERR,
		    "dm is not configured for this slot type");
		mm_response_error(cmd,
		    ECLASS_COMPAT,
		    "ECARTDRVSLOTMISMATCH",
		    MM_5097_MSG,
		    NULL);
		mm_clear_db(&dm);
		mm_clear_db(&dm_shape);
		return (NULL);
	}

	mm_clear_db(&dm_shape);

	drive = NULL;
	drive = (cmi_drive_list_t *)
	    calloc(1,
	    sizeof (cmi_drive_list_t));
	if (drive == NULL) {
		mms_trace(MMS_ERR,
		    "Unable to malloc"\
		    " cmi_drive_list: %s",
		    strerror(errno));
		mm_system_error(cmd,
		    "unable to allocate mem for drive stat");
		mm_clear_db(&dm);
		return (NULL);
	}
	drive->cmi_drive_name =
	    strdup(candidate_drive);
	drive->cmi_mode_valid = 1;
	drive->cmi_drive_not_ready = drive_not_ready;
	drive->cmi_drive_used = 0;

	drive->cmi_dm_name =
	    strdup(PQgetvalue(dm,
	    0, 0));
	drive->cmi_dm_shape_priority = dm_shape_priority;
	drive->cmi_dm_density_priority = dm_density_priority;
	/* Column references must match what is in mm_mount_init_candidates */
	drive->cmi_drv_priority = atoi(PQgetvalue(drive_results,
	    drive_row, 2));
	drive->cmi_drv_num_mounts = atoi(PQgetvalue(drive_results,
	    drive_row, 3));


	/* Insert Drives into the correct place in the list here */
	/* Drives are already orderd by priority and number mounts */
	/* Enforce shape and density priority here */
	/* Go down the drive list and find where this */
	/* drive's pritoriy group starts */
	/* Then insert the current drive according to dm_shape_priority */
	/* Maintain the original ordering within like prioritys */
	if (mm_insert_next_drive(&cart->cmi_drive_list,
	    drive)) {
		mms_trace(MMS_ERR,
		    "error inserting drive into list");
		mm_free_cmi_drive(drive);
		drive = NULL;
	}
	mm_clear_db(&dm);
	return (drive);
}

cmi_cart_list_t *
mm_setup_cart(mm_command_t *cmd,
    mm_db_t *db,
    PGresult *cart_results,
    int row_number) {

	cmi_cart_list_t		*cart = NULL;
	cmd_mount_info_t	*mount_info = &cmd->cmd_mount_info;

	/* Column references must match what is in mm_mount_cart_results */
	char *candidate_cartid = PQgetvalue(cart_results, row_number, 0);
	char *candidate_library = PQgetvalue(cart_results, row_number, 1);
	char *candidate_priority = PQgetvalue(cart_results, row_number, 2);
	char *candidate_num_mounts = PQgetvalue(cart_results, row_number, 3);
	char *cart_type = PQgetvalue(cart_results, row_number, 4);
	char *cart_pcl = PQgetvalue(cart_results, row_number, 5);
	char *cart_loaded = PQgetvalue(cart_results, row_number, 6);

	PGresult *partition_results;
	char *bit_format = NULL;

	/* Get PARTITION."PartitionBitFormat" */
	if (mm_db_exec(HERE, db,
	    "select \"PARTITION\".\"PartitionBitFormat\" "
	    "from \"PARTITION\" where \"CartridgeID\" = '%s';",
	    candidate_cartid) != MM_DB_DATA) {
		mm_sql_db_err_rsp_new(cmd, db);
		mms_trace(MMS_ERR,
		    "db error getting PartitionBitFormat");
		return (NULL);
	}
	partition_results = db->mm_db_results;
	if (PQntuples(partition_results) == 0) {
		mms_trace(MMS_ERR,
		    "couldn't find PARTITION for %s",
		    candidate_cartid);
		mm_system_error(cmd,
		    "couldn't find PARTITION");
		mm_clear_db(&partition_results);
		return (NULL);
	}
	bit_format = PQgetvalue(db->mm_db_results, 0, 0);


	cart = (cmi_cart_list_t *)
	    calloc(1, sizeof (cmi_cart_list_t));
	if (cart == NULL) {
		mms_trace(MMS_ERR,
		    "Unable to malloc cmi_cart_list: %s",
		    strerror(errno));
		mm_system_error(cmd,
		    "unable to allocate mem for drive list");
		mm_clear_db(&partition_results);
		return (NULL);
	}
	mms_list_create(&cart->cmi_drive_list,
	    sizeof (cmi_drive_list_t),
	    offsetof(cmi_drive_list_t,
	    cmi_drive_next));

	strcpy(cart->cmi_cart_id, candidate_cartid);
	cart->cmi_library = NULL;
	cart->cmi_library = mms_strapp(cart->cmi_library,
	    candidate_library);
	cart->cmi_cart_pcl = mms_strapp(cart->cmi_cart_pcl,
	    cart_pcl);
	cart->cmi_cart_type = mms_strapp(cart->cmi_cart_type,
	    cart_type);
	cart->cmi_bit_format = mms_strapp(cart->cmi_bit_format,
	    bit_format);

	cart->cmi_cart_not_ready = 0;
	cart->cmi_cart_used = 0;

	cart->cmi_cart_priority = atoi(candidate_priority);
	cart->cmi_cart_num_mounts = atoi(candidate_num_mounts);
	if ((strcmp(cart_loaded, "true") == 0) ||
	    (strcmp(cart_loaded, "t") == 0)) {
		cart->cmi_cart_loaded = 1;
	} else {
		cart->cmi_cart_loaded = 0;
	}

	mms_list_insert_tail(&mount_info->cmi_cart_list,
	    cart);

	mm_clear_db(&partition_results);
	return (cart);
}

int
mm_mount_candidate_loaded(mm_command_t *cmd) {

	/*
	 * this function needs to determine if a candidate
	 * cartridge is already loaded into a candidate drive.
	 * If there is, it must set the mount_info
	 * for the cart/lib/drive/dm
	 */

	cmd_mount_info_t	*mount_info = &cmd->cmd_mount_info;

	cmi_cart_list_t		*cart = NULL;
	cmi_drive_list_t	*drive = NULL;

	char			*cur_pcl = NULL;
	char			*cur_cartid = NULL;
	char			*cur_library = NULL;
	char			*cur_dm = NULL;
	char			*cur_drive = NULL;

	char			*drive_pcl = NULL;

	mms_trace(MMS_DEVP,
	    "mm_mount_candidate_loaded: ");

	mount_info->cmi_mount_cart_loaded = 0;

	/* The list should already be ordered */
	/* select the 1st available */
	mms_list_foreach(&mount_info->cmi_cart_list, cart) {
		cur_pcl = cart->cmi_cart_pcl;
		cur_library = cart->cmi_library;
		cur_cartid = cart->cmi_cart_id;
		/* The list should already be ordered */
		/* select the 1st available */
		if (cart->cmi_cart_not_ready ||
		    cart->cmi_cart_used) {
			continue;
		}
		mms_list_foreach(&cart->cmi_drive_list, drive) {
			if (drive->cmi_drive_not_ready ||
			    drive->cmi_drive_used) {
				continue;
			}
			if (drive->cmi_drive_loaded) {
				drive_pcl = drive->cmi_loaded_pcl;
				cur_drive = drive->cmi_drive_name;
				cur_dm = drive->cmi_dm_name;
				if (strcmp(cur_pcl, drive_pcl) == 0) {
					/* set this mount info and return */
					mm_set_mount_info_cart(cur_cartid,
					    mount_info);
					mm_set_mount_info_drive(cur_drive,
					    mount_info);
					mm_set_mount_info_dm(cur_dm,
					    mount_info);
					mm_set_mount_info_library(cur_library,
					    mount_info);
					mount_info->cmi_mount_cart_loaded = 1;
					return (1);
				}
			}
		}
	}
	return (0);

}
int
mm_mount_open_drive(mm_command_t *cmd) {
	/*
	 * this function needs to determine if there is an
	 * open drive for a candidate cartridge
	 * If there is, it must set the mount_info
	 * for the cart/lib/drive/dm
	 */
	cmd_mount_info_t	*mount_info = &cmd->cmd_mount_info;

	cmi_cart_list_t		*cart = NULL;
	cmi_drive_list_t	*drive = NULL;

	char			*cur_cartid = NULL;
	char			*cur_library = NULL;
	char			*cur_dm = NULL;
	char			*cur_drive = NULL;

	mms_trace(MMS_DEVP,
	    "mm_mount_open_drive: ");

	/* The list should already be ordered */
	/* select the 1st available */
	mms_list_foreach(&mount_info->cmi_cart_list, cart) {
		if (cart->cmi_cart_not_ready ||
		    cart->cmi_cart_used) {
			continue;
		}
		cur_library = cart->cmi_library;
		cur_cartid = cart->cmi_cart_id;
		/* only look at non loaded carts */
		if (cart->cmi_cart_loaded) {
			continue;
		}
		/* The list should already be ordered */
		/* select the 1st available */
		mms_list_foreach(&cart->cmi_drive_list, drive) {
			if (drive->cmi_drive_not_ready ||
			    drive->cmi_drive_used) {
				continue;
			}
			/* only look at non-loaded drives */
			if (drive->cmi_drive_loaded) {
				continue;
			}
			cur_drive = drive->cmi_drive_name;
			cur_dm = drive->cmi_dm_name;
			/* set this mount info and return */
			mm_set_mount_info_cart(cur_cartid,
			    mount_info);
			mm_set_mount_info_drive(cur_drive,
			    mount_info);
			mm_set_mount_info_dm(cur_dm,
			    mount_info);
			mm_set_mount_info_library(cur_library,
			    mount_info);
			return (1);
		}
	}
	return (0);

}

int
mm_unmount_2_drive(mm_command_t *cmd, mm_db_t *db) {
	/* check if a loaded candidate cartridge */
	/* must be mounted in a drive loaded with a non-candidate */
	/* need unmount candidate drive and candidate cart */
	/* then mount */

	cmd_mount_info_t	*mount_info = &cmd->cmd_mount_info;

	cmi_cart_list_t		*cart = NULL;
	cmi_drive_list_t	*drive = NULL;

	char			*cur_cartid = NULL;
	char			*cur_pcl = NULL;
	char			*cur_library = NULL;
	char			*cur_dm = NULL;
	char			*cur_drive = NULL;

	mms_trace(MMS_DEVP,
	    "mm_unmount_2_drive: ");

	mms_list_foreach(&mount_info->cmi_cart_list, cart) {
		if (cart->cmi_cart_not_ready ||
		    cart->cmi_cart_used) {
			continue;
		}
		cur_library = cart->cmi_library;
		cur_cartid = cart->cmi_cart_id;
		cur_pcl = cart->cmi_cart_pcl;
		mms_list_foreach(&cart->cmi_drive_list, drive) {
			if (drive->cmi_drive_not_ready ||
			    drive->cmi_drive_used) {
				continue;
			}
			cur_drive = drive->cmi_drive_name;
			cur_dm = drive->cmi_dm_name;
			if (cart->cmi_cart_loaded &&
			    drive->cmi_drive_loaded) {
				if (mm_db_exec(HERE, db,
				    "select \"LibraryName\",\"DriveName\" "
				    "from \"DRIVE\" where \"DRIVE\"."
				    "\"CartridgePCL\" = '%s' and "
				    "\"DRIVE\".\"DriveName\" = '%s';",
				    cur_pcl, cur_drive) != MM_DB_DATA) {
					mms_trace(MMS_ERR,
					    "mm_unmount_2_drive:"
					    " db error reading data");
					mm_clear_db(&db->mm_db_results);
					continue;
				}

				if (PQntuples(db->mm_db_results) == 0) {
					/* Cur cart is not loaded */
					mms_trace(MMS_ERR,
					    "%s not found in drive %s",
					    cur_pcl, cur_drive);
					mm_clear_db(&db->mm_db_results);
					continue;
				}

				mm_set_mount_info_cart(cur_cartid,
				    mount_info);
				mm_set_mount_info_drive(cur_drive,
				    mount_info);
				mm_set_mount_info_dm(cur_dm,
				    mount_info);
				mm_set_mount_info_library(cur_library,
				    mount_info);
				mms_trace(MMS_DEVP,
				    "** 2 Unmount Summary **");
				mms_trace(MMS_DEVP,
				    "1st unmount %s %s",
				    cur_library,
				    cur_drive);
				mms_trace(MMS_DEVP,
				    "2nd unmount %s %s",
				    PQgetvalue(db->mm_db_results, 0, 0),
				    PQgetvalue(db->mm_db_results, 0, 1));

				mount_info->cmi_first_lib =
				    strdup(cur_library);
				mount_info->cmi_first_drive =
				    strdup(cur_drive);
				mount_info->cmi_second_lib =
				    strdup(PQgetvalue(db->mm_db_results, 0, 0));
				mount_info->cmi_second_drive =
				    strdup(PQgetvalue(db->mm_db_results, 0, 1));


				mm_clear_db(&db->mm_db_results);
				return (1);
			}
		}
	}
	return (0);

}

int
mm_mount_loaded_drive(mm_command_t *cmd, mm_db_t *db,
    char **drive_to_unload, char **lib_to_unload) {
	/*
	 * this function needs to determine if a candidate
	 * cartridge must be mounted on a drive already loaded
	 * with a non-candidate cartridge that needs to be unmounted
	 * OR
	 * If a candidate cartridge is loaded in a non-candidate drive
	 * that 1st must be unmounted
	 * If there is, it must set the mount_info
	 * for the cart/lib/drive/dm
	 */
	cmd_mount_info_t	*mount_info = &cmd->cmd_mount_info;

	cmi_cart_list_t		*cart = NULL;
	cmi_drive_list_t	*drive = NULL;

	char			*cur_cartid = NULL;
	char			*cur_pcl = NULL;
	char			*cur_library = NULL;
	char			*cur_dm = NULL;
	char			*cur_drive = NULL;

	mms_trace(MMS_DEVP,
	    "mm_mount_loaded_drive: ");

	/* The list should already be ordered */
	/* select the 1st available */
	mms_list_foreach(&mount_info->cmi_cart_list, cart) {
		if (cart->cmi_cart_not_ready ||
		    cart->cmi_cart_used) {
			continue;
		}
		cur_library = cart->cmi_library;
		cur_cartid = cart->cmi_cart_id;
		cur_pcl = cart->cmi_cart_pcl;

		/* If the cartridge is not mounted */

		/* The list should already be ordered */
		/* select the 1st available */

		mms_list_foreach(&cart->cmi_drive_list, drive) {
			if (drive->cmi_drive_not_ready ||
			    drive->cmi_drive_used) {
				continue;
			}
			cur_drive = drive->cmi_drive_name;
			cur_dm = drive->cmi_dm_name;

			if (cart->cmi_cart_loaded &&
			    (drive->cmi_drive_loaded == 0)) {
				/* Candidate is loaded and drive is empty */

				/* this candidate cart is loaded in a drive */
				/* Get the lib/drive name where */
				/* this cartridge is mounted */
				if (mm_db_exec(HERE, db,
				    "select \"LibraryName\",\"DriveName\" "
				    "from \"DRIVE\" where \"DRIVE\"."
				    "\"CartridgePCL\" = '%s';",
				    cur_pcl) != MM_DB_DATA) {
					mms_trace(MMS_ERR,
					    "mm_mount_loaded_drive: "
					    "db error getting data");
					continue;
				}

				if (PQntuples(db->mm_db_results) == 0) {
					/* Cur cart is not loaded */
					mms_trace(MMS_ERR,
					    "%s not found in a drive",
					    cur_pcl);
					mm_clear_db(&db->mm_db_results);
					continue;
				} else {
					/* cur cart is loaded */
					*(drive_to_unload) =
					    mms_strapp(*(drive_to_unload),
					    PQgetvalue(db->mm_db_results,
					    0, 1));
					*(lib_to_unload) =
					    mms_strapp(*(lib_to_unload),
					    PQgetvalue(db->mm_db_results,
					    0, 0));
					mms_trace(MMS_DEVP,
					    "%s loaded in %s %s",
					    cur_pcl,
					    PQgetvalue(db->mm_db_results,
					    0, 0),
					    PQgetvalue(db->mm_db_results,
					    0, 1));
				}
				mm_clear_db(&db->mm_db_results);

				mm_set_mount_info_cart(cur_cartid,
				    mount_info);
				mm_set_mount_info_drive(cur_drive,
				    mount_info);
				mm_set_mount_info_dm(cur_dm,
				    mount_info);
				mm_set_mount_info_library(cur_library,
				    mount_info);
				return (1);

			} else if ((cart->cmi_cart_loaded == 0) &&
			    (drive->cmi_drive_loaded == 1)) {

				/* set this mount info and return */
				*(drive_to_unload) = NULL;
				*(lib_to_unload) = NULL;
				mm_set_mount_info_cart(cur_cartid,
				    mount_info);
				mm_set_mount_info_drive(cur_drive,
				    mount_info);
				mm_set_mount_info_dm(cur_dm,
				    mount_info);
				mm_set_mount_info_library(cur_library,
				    mount_info);
				return (1);
			}
		}
	}
	return (0);
}

int
mm_set_immediate_unmount(mm_command_t *cmd, mm_db_t *db) {

	cmd_mount_info_t	*mount_info = &cmd->cmd_mount_info;

	cmi_cart_list_t		*cart = NULL;
	cmi_drive_list_t	*drive = NULL;

	char			*cur_cartid = NULL;
	char			*cur_library = NULL;
	char			*cur_dm = NULL;
	char			*cur_drive = NULL;


	int			rc = MM_CMD_DONE;


	/* The list should already be ordered */
	/* select the 1st available */

	cart = mms_list_head(&mount_info->cmi_cart_list);
	if (cart == NULL) {
		mms_trace(MMS_ERR,
		    "internal error setting cmi info, "
		    "cannot find candidate carts structfound");
		mm_system_error(cmd,
		    "internal error setting cmi info, "
		    "no candidate carts found");
		return (MM_CMD_ERROR);
	}
	cur_library = cart->cmi_library;
	cur_cartid = cart->cmi_cart_id;

	drive = mms_list_head(&cart->cmi_drive_list);
	if (drive == NULL) {
		mms_trace(MMS_ERR,
		    "internal error setting cmi info, "
		    "no candidate drives found");
		mm_system_error(cmd,
		    "internal error setting cmi info, "
		    "no candidate drives found");
		return (MM_CMD_ERROR);
	}

	cur_drive = drive->cmi_drive_name;
	cur_dm = drive->cmi_dm_name;


	mm_set_mount_info_cart(cur_cartid,
	    mount_info);
	mm_set_mount_info_drive(cur_drive,
	    mount_info);
	mm_set_mount_info_dm(cur_dm,
	    mount_info);
	mm_set_mount_info_library(cur_library,
	    mount_info);
	if (mount_info->cmi_pcl == NULL) {
		mount_info->cmi_pcl =
		    mm_get_cart_pcl(cmd, mount_info->cmi_cartridge, db);
	}
	/* Select Is done - print the results */
	mms_trace(MMS_DEVP, "Cart/Lib/Drive selection "
	    "complete for task %s",
	    cmd->cmd_uuid);
	mms_trace(MMS_DEVP, "Cartridge ID is %s",
	    mount_info->cmi_cartridge);
	mms_trace(MMS_DEVP, "Cartridge PCL is %s",
	    mount_info->cmi_pcl);
	mms_trace(MMS_DEVP, "Library is %s",
	    mount_info->cmi_library);
	mms_trace(MMS_DEVP, "Drive is %s",
	    mount_info->cmi_drive);
	mms_trace(MMS_DEVP, "DM is %s",
	    mount_info->cmi_dm);

	if (mm_db_exec(HERE, db, "delete from \"TASK\" "
	    "where \"TaskID\" = '%s';",
	    cmd->cmd_uuid) != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_immediate_unmount: "
		    "db error removing TASK");
	}

	if (mm_new_tm_task(db, cmd, "dispatched") != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_immediate_unmount: "
		    "db error creating TASK");
	}

	/* Delete all old TASK objects and create them anew */
	if (mm_db_exec(HERE, db, "delete from \"TASKDRIVE\" "
	    "where \"TaskID\" = '%s';",
	    cmd->cmd_uuid) != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_immediate_unmount: "
		    "db error removing TASKDRIVE");
	}
	if (mm_db_exec(HERE, db, "delete from \"TASKLIBRARY\" "
	    "where \"TaskID\" = '%s';",
	    cmd->cmd_uuid) != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_immediate_unmount: "
		    "db error removing TASKLIBRARY");
	}
	if (mm_db_exec(HERE, db, "delete from \"TASKCARTRIDGE\" "
	    "where \"TaskID\" = '%s';",
	    cmd->cmd_uuid) != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_immediate_unmount: "
		    "db error removing TASKCARTRIDGE");
	}


	if (mm_set_tm_drive(db,
	    cmd->cmd_uuid,
	    mount_info->cmi_drive) != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_immediate_unmount: "
		    "db error setting TASKDRIVE");
	}
	if (mm_set_tm_library(db,
	    cmd->cmd_uuid,
	    mount_info->cmi_library) != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_immediate_unmount: "
		    "db error setting TASKLIBRARY");
	}

	if (mm_set_tm_cartridge(db,
	    cmd->cmd_uuid,
	    mount_info->cmi_cartridge) != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_immediate_unmount: "
		    "db error setting TASKCARTRIDGE");
	}

	if (mm_db_exec(HERE, db, "update \"DRIVE\""
	    "set \"DriveStateSoft\" = 'in use'"
	    "where \"DriveName\" = '%s';",
	    mount_info->cmi_drive) != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_immediate_unmount: "
		    "db error setting DriveStateSoft");
	}
	if (mm_db_exec(HERE, db, "update \"DRIVE\""
	    "set \"DMName\" = '%s' "
	    "where \"DriveName\" = '%s';",
	    mount_info->cmi_dm,
	    mount_info->cmi_drive) != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_immediate_unmount: "
		    "db error setting DMName");
	}

	if (mm_db_exec(HERE, db,
	    "update \"CARTRIDGE\" set "
	    "\"CartridgeStatus\" = 'in use' "
	    "where \"CartridgeID\" = '%s';",
	    mount_info->cmi_cartridge) != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_immediate_unmount: "
		    "db error setting CartridgeStatus");
	}


	return (rc);

}
void
mm_set_mount_objs(mm_command_t *cmd, mm_db_t *db) {
	cmd_mount_info_t	*mount_info = &cmd->cmd_mount_info;



	if (mm_db_exec(HERE, db, "delete from \"TASK\" "
	    "where \"TaskID\" = '%s';",
	    cmd->cmd_uuid) != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_mount_objs: "
		    "db error deleting TASK");
	}

	/* Delete all old TASK objects and create them anew */
	if (mm_db_exec(HERE, db, "delete from \"TASKDRIVE\" "
	    "where \"TaskID\" = '%s';",
	    cmd->cmd_uuid) != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_mount_objs: "
		    "db error deleting TASKDRIVE");
	}
	if (mm_db_exec(HERE, db, "delete from \"TASKLIBRARY\" "
	    "where \"TaskID\" = '%s';",
	    cmd->cmd_uuid) != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_mount_objs: "
		    "db error deleting TASKLIBRARY");
	}
	if (mm_db_exec(HERE, db, "delete from \"TASKCARTRIDGE\" "
	    "where \"TaskID\" = '%s';",
	    cmd->cmd_uuid) != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_mount_objs: "
		    "db error deleting TASKCARTRIDGE");
	}

	if ((mount_info->cmi_drive == NULL) ||
	    (mount_info->cmi_library == NULL) ||
	    (mount_info->cmi_cartridge == NULL) ||
	    (mount_info->cmi_dm == NULL)) {
		mms_trace(MMS_ERR,
		    "mm_set_mount_objs: "
		    "mount info incomplete");
		mm_system_error(cmd,
		    "internal error setting task info, "
		    "mount info incomplete");
		return;
	}

	if (mm_new_tm_task(db, cmd, "dispatched") != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_mount_objs: "
		    "db error inserting TASK");
	}

	if (mm_set_tm_drive(db,
	    cmd->cmd_uuid,
	    mount_info->cmi_drive) != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_mount_objs: "
		    "db error inserting TASKDRIVE");
	}
	if (mm_set_tm_library(db,
	    cmd->cmd_uuid,
	    mount_info->cmi_library) != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_mount_objs: "
		    "db error inserting TASKLIBRARY");
	}
	if (mm_set_tm_cartridge(db,
	    cmd->cmd_uuid,
	    mount_info->cmi_cartridge) != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_mount_objs: "
		    "db error inserting TASKCARTRIDGE");
	}

	if (mm_db_exec(HERE, db, "update \"DRIVE\""
	    "set \"DriveStateSoft\" = 'in use'"
	    "where \"DriveName\" = '%s';",
	    mount_info->cmi_drive) != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_mount_objs: "
		    "db error updating DriveStateSoft");
	}
	if (mm_db_exec(HERE, db, "update \"DRIVE\""
	    "set \"DMName\" = '%s' "
	    "where \"DriveName\" = '%s';",
	    mount_info->cmi_dm,
	    mount_info->cmi_drive) != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_mount_objs: "
		    "db error updating DMName");
	}

	if (mm_db_exec(HERE, db,
	    "update \"CARTRIDGE\" set "
	    "\"CartridgeStatus\" = 'in use' "
	    "where \"CartridgeID\" = '%s';",
	    mount_info->cmi_cartridge) != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_mount_objs: "
		    "db error updating CartridgeStatus");
	}

}

int
mm_dispatch_now(mm_wka_t *mm_wka, mm_command_t *cmd, mm_db_t *db) {
	cmd_mount_info_t	*mount_info = &cmd->cmd_mount_info;
	mm_command_t		*unmnt_cmd_1 = NULL;
	mm_command_t		*unmnt_cmd_2 = NULL;

	/* This function is used to setup the command */
	/* flags and depend pointers for the mount */

	/* Need to set error message in this function */
	if (mount_info->cmi_mount_type ==
	    MM_CANDIDATE_LOADED) {
		mms_trace(MMS_DEVP,
		    "MM_CANDIDATE_LOADED");
		/* Remove the delay unload command */
		(void) mm_remove_unload(mount_info->cmi_library,
		    mount_info->cmi_drive,
		    mm_wka->mm_data);
		return (0);
	}
	if (mount_info->cmi_mount_type ==
	    MM_OPEN_DRIVE) {
		mms_trace(MMS_DEVP,
		    "MM_OPEN_DRIVE");
		return (0);
	}
	if (mount_info->cmi_mount_type ==
	    MM_UNMOUNT_DRIVE) {
		mms_trace(MMS_DEVP,
		    "MM_UNMOUNT_DRIVE");
		/* Set the delay unload for immdiate dispatch */
		if (mm_dispatch_unload(mount_info->cmi_library,
		    mount_info->cmi_drive,
		    cmd,
		    mm_wka->mm_data) == NULL) {
			/* Instead of return error */
			/* attempt to fix by adding a clear_drive */
			/* for this drive, set this */
			/* command as parent of */
			/* the clear drive */
			mms_trace(MMS_ERR,
			    "could not find delay unload, "
			    "attempt to clear and continue");
			if (mm_add_clear_drive(mount_info->cmi_drive,
			    mm_wka->mm_data,
			    db, cmd, NULL, 1, 0) == NULL) {
				mm_system_error(cmd,
				    "error adding clear drive cmd");
				return (1);
			}
		}
		MM_UNSET_FLAG(cmd->cmd_flags, MM_CMD_DISPATCHABLE);
		return (0);
	}
	if (mount_info->cmi_mount_type ==
	    MM_UNMOUNT_CART) {
		mms_trace(MMS_DEVP,
		    "MM_UNMOUNT_CART");
		/* Set the delay unload for immdiate dispatch */
		if (mm_dispatch_unload(mount_info->
		    cmi_first_lib,
		    mount_info->cmi_first_drive,
		    cmd,
		    mm_wka->mm_data) == NULL) {
			/* Instead of return error */
			/* attempt to fix by adding a clear_drive */
			/* for this drive, set this */
			/* command as parent of */
			/* the clear drive */
			mms_trace(MMS_ERR,
			    "could not find delay unload, "
			    "attempt to clear and continue");
			if (mm_add_clear_drive(mount_info->
			    cmi_first_drive,
			    mm_wka->mm_data,
			    db, cmd, NULL, 1, 0) == NULL) {
				mm_system_error(cmd,
				    "error adding clear drive cmd");
				return (1);
			}
		}
		MM_UNSET_FLAG(cmd->cmd_flags, MM_CMD_DISPATCHABLE);
		return (0);
	}
	if (mount_info->cmi_mount_type ==
	    MM_UNMOUNT_2) {
		mms_trace(MMS_DEVP,
		    "MM_UNMOUNT_2");
		if ((unmnt_cmd_1 =
		    mm_dispatch_unload(mount_info->cmi_first_lib,
		    mount_info->cmi_first_drive,
		    NULL,
		    mm_wka->mm_data)) == NULL) {
			mms_trace(MMS_ERR,
			    "error finding unmount command");

			if ((unmnt_cmd_1 =
			    mm_add_clear_drive(mount_info->cmi_first_drive,
			    mm_wka->mm_data,
			    db, cmd, NULL, 1, 0)) == NULL) {
				mm_system_error(cmd,
				    "error adding clear drive cmd");
				return (1);
			}
		}

		if ((unmnt_cmd_2 =
		    mm_return_unload(mount_info->cmi_second_lib,
		    mount_info->cmi_second_drive,
		    mm_wka->mm_data)) == NULL) {
			mms_trace(MMS_ERR,
			    "error finding unmount command");
			if ((unmnt_cmd_2 =
			    mm_add_clear_drive(mount_info->cmi_second_drive,
			    mm_wka->mm_data,
			    db, cmd, NULL, 1, 0)) == NULL) {
				mm_system_error(cmd,
				    "error adding clear drive cmd");
				return (1);
			}
		}
		mm_add_depend(unmnt_cmd_1, unmnt_cmd_2);
		mm_add_depend(unmnt_cmd_2, cmd);
		MM_SET_FLAG(unmnt_cmd_1->cmd_flags,
		    MM_CMD_DISPATCHABLE);
		MM_UNSET_FLAG(unmnt_cmd_2->cmd_flags,
		    MM_CMD_DISPATCHABLE);
		MM_UNSET_FLAG(cmd->cmd_flags,
		    MM_CMD_DISPATCHABLE);
		return (0);
	}
	mm_system_error(cmd,
	    "encountered unknown mount type");
	return (1);

}

int
mm_set_immediate_mount(mm_wka_t *mm_wka, mm_command_t *cmd, mm_db_t *db) {
	cmd_mount_info_t	*mount_info = &cmd->cmd_mount_info;

	int			rc = MM_CMD_DONE;

	char			*drive_to_unload = NULL;
	char			*lib_to_unload = NULL;

	mms_trace(MMS_DEVP, "mm_set_immediate_mount");

	/* select the exact cart/drive/dm/lib combination */

	/* Every candidate is currently in a ready state */
	/* Drives may be loaded with a cartridge */
	/* Cartridge could be: */
	/* a. a non-candidate cartridge */
	/* b. a candidate cartridge */

	/* If a candidate drive has a candidate loaded, use that now */
	/* If their are no candidate cartridge's loaded, */
	/* try to find an open drive */
	/* If there are no open drives, use a drive loaded */
	/* with a non-candidate cartridge */

	if (mm_mount_candidate_loaded(cmd)) {
		/* 0 mount time */
		mms_trace(MMS_DEVP,
		    "a candidate cartridge is loaded");
		mount_info->cmi_mount_type =
		    MM_CANDIDATE_LOADED;
	} else if (mm_mount_open_drive(cmd)) {
		/* 1 mount time */
		mms_trace(MMS_DEVP,
		    "open drive found");
		mount_info->cmi_mount_type =
		    MM_OPEN_DRIVE;
	} else if (mm_mount_loaded_drive(cmd, db, &drive_to_unload,
	    &lib_to_unload)) {
		/* 2 mount time */
		/* these mounts need an unmount, then mount */
		if (drive_to_unload == NULL &&
		    lib_to_unload == NULL) {
			mount_info->cmi_mount_type =
			    MM_UNMOUNT_DRIVE;
			mms_trace(MMS_DEVP,
			    "drive loaded with non-candidate "
			    "must unload 1st");
			/* Need to set up parent command */
			/* return as dispatch depend */
			mms_trace(MMS_DEVP,
			    "%s needs unload to complete first",
			    mount_info->cmi_drive);
			MM_UNSET_FLAG(cmd->cmd_flags,
			    MM_CMD_DISPATCHABLE);
			rc = MM_DISPATCH_DEPEND;
		} else {
			mms_trace(MMS_DEVP,
			    "candidate loaded in non-candidate drive "
			    "must unload 1st");
			mount_info->cmi_mount_type =
			    MM_UNMOUNT_CART;
			mount_info->cmi_first_drive =
			    strdup(drive_to_unload);
			mount_info->cmi_first_lib =
			    strdup(lib_to_unload);

			/* Need to set up parent command */
			/* return as dispatch depend */
			mms_trace(MMS_DEVP,
			    "%s needs unload to complete first",
			    drive_to_unload);
			MM_UNSET_FLAG(cmd->cmd_flags,
			    MM_CMD_DISPATCHABLE);
			rc = MM_DISPATCH_DEPEND;
			free(drive_to_unload);
			free(lib_to_unload);
		}

	} else if (mm_unmount_2_drive(cmd, db)) {
		mount_info->cmi_mount_type =
		    MM_UNMOUNT_2;
		/* 3 mount time  */
		/* Candidate cart is mounted, */
		/* the only candidate drive is loaded with non-candidate */
		/* need to unmount candidate cart, unmount candidate drive */
		/* then mount candidate cart/drive */
		MM_UNSET_FLAG(cmd->cmd_flags, MM_CMD_DISPATCHABLE);
		rc = MM_DISPATCH_DEPEND;
	} else {

		/* should never reach herer */
		mms_trace(MMS_ERR,
		    "MMS_ERROR - no drives found");
		mm_system_error(cmd,
		    "internal error, "
		    "could not find ready drive, "
		    "submitt a bug if you hit this!,"
		    "MM internal states out of sync");
		mms_trace(MMS_INFO, "mm_set_immediate_mount: "
		    "returning MM_RESYNC");
		return (MM_RESYNC);

	}

	if (mount_info->cmi_pcl == NULL) {
		mount_info->cmi_pcl =
		    mm_get_cart_pcl(cmd, mount_info->cmi_cartridge, db);
	}

	/*  call function to kick off delay unmounts */

	if (mm_dispatch_now(mm_wka, cmd, db)) {
		/* error should be set */
		mms_trace(MMS_ERR,
		    "error setting up mount for dispatch");
		return (MM_CMD_ERROR);
	}

	/* Select Is done - print the results */
	mms_trace(MMS_DEVP, "Cart/Lib/Drive selection "
	    "complete for task %s",
	    cmd->cmd_uuid);
	mms_trace(MMS_DEVP, "Cartridge ID is %s",
	    mount_info->cmi_cartridge);
	mms_trace(MMS_DEVP, "Cartridge PCL is %s",
	    mount_info->cmi_pcl);
	mms_trace(MMS_DEVP, "Library is %s",
	    mount_info->cmi_library);
	mms_trace(MMS_DEVP, "Drive is %s",
	    mount_info->cmi_drive);
	mms_trace(MMS_DEVP, "DM is %s",
	    mount_info->cmi_dm);

	if (mm_db_exec(HERE, db, "delete from \"TASK\" "
	    "where \"TaskID\" = '%s';",
	    cmd->cmd_uuid) != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_immediate_mount: "
		    "db error removing TASK");
	}

	if (mm_new_tm_task(db, cmd, "dispatched") != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_immediate_mount: "
		    "db error creating TASK");
	}

	/* Delete all old TASK objects and create them anew */
	if (mm_db_exec(HERE, db, "delete from \"TASKDRIVE\" "
	    "where \"TaskID\" = '%s';",
	    cmd->cmd_uuid) != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_immediate_mount: "
		    "db error removing TASKDRIVE");
	}
	if (mm_db_exec(HERE, db, "delete from \"TASKLIBRARY\" "
	    "where \"TaskID\" = '%s';",
	    cmd->cmd_uuid) != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_immediate_mount: "
		    "db error removing TASKLIBRARY");
	}
	if (mm_db_exec(HERE, db, "delete from \"TASKCARTRIDGE\" "
	    "where \"TaskID\" = '%s';",
	    cmd->cmd_uuid) != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_immediate_mount: "
		    "db error removing TASKCARTRIDGE");
	}


	if (mm_set_tm_drive(db,
	    cmd->cmd_uuid,
	    mount_info->cmi_drive) != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_immediate_mount: "
		    "db error creating TASKDRIVE");
	}
	if (mm_set_tm_library(db,
	    cmd->cmd_uuid,
	    mount_info->cmi_library) != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_immediate_mount: "
		    "db error creating TASKLIBRARY");
	}
	if (mm_set_tm_cartridge(db,
	    cmd->cmd_uuid,
	    mount_info->cmi_cartridge) != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_immediate_mount: "
		    "db error creating TASKCARTRIDGE");
	}

	if (mm_db_exec(HERE, db, "update \"DRIVE\""	\
	    "set \"DriveStateSoft\" = 'in use'"	\
	    "where \"DriveName\" = '%s';",
	    mount_info->cmi_drive) != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_immediate_mount: "
		    "db error updating DriveStateSoft");
	}
	if (mm_db_exec(HERE, db, "update \"DRIVE\""\
	    "set \"DMName\" = '%s' "\
	    "where \"DriveName\" = '%s';",
	    mount_info->cmi_dm,
	    mount_info->cmi_drive) != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_immediate_mount: "
		    "db error updating DMName");
	}
	if (mm_db_exec(HERE, db,
	    "update \"CARTRIDGE\" set "
	    "\"CartridgeStatus\" = 'in use' "
	    "where \"CartridgeID\" = '%s';",
	    mount_info->cmi_cartridge) != MM_DB_OK) {
		mms_trace(MMS_ERR,
		    "mm_set_immediate_mount: "
		    "db error updating CartridgeStatus");
	}


	return (rc);


}


int
mm_parse_mount_cmd(mm_wka_t *mm_wka, mm_command_t *cmd) {

	cci_t			*conn = &mm_wka->wka_conn;
	cmd_mount_info_t	*mount_info = &cmd->cmd_mount_info;

	mms_par_node_t		*arg;
	mms_par_node_t		*value;
	mms_par_node_t		*work = NULL;
	mms_par_node_t		*item = NULL;
	int			go;
	int			count;

	char			*dm_host;

	cmi_mode_list_t		*mode = NULL;

	mms_trace(MMS_DEVP, "mm_parse_mount_cmd");
	mount_info->cmi_operation = MM_MOUNT;


	/* Get the type */
	mms_trace(MMS_DEVP, "type");
	MMS_PN_LOOKUP(arg, cmd->cmd_root, "type",
	    MMS_PN_CLAUSE, NULL);
	MMS_PN_LOOKUP(value, arg, NULL, MMS_PN_KEYWORD, NULL);
	if (strcmp(value->pn_string, "SIDE") == 0) {
		mount_info->cmi_type = MM_SIDE;
	} else if (strcmp(value->pn_string, "PARTITION") == 0) {
		mount_info->cmi_type = MM_PARTITION;
	} else if (strcmp(value->pn_string, "VOLUME") == 0) {
		mount_info->cmi_type = MM_VOLUME;
	} else {
		mms_trace(MMS_ERR, "Invalid mount type specified");
		mm_response_error(cmd,
		    EINVALIDTYPE,
		    ESYNTAX,
		    MM_5051_MSG,
		    NULL);
		return (MM_CMD_ERROR);
	}

	/* Get when */
	mms_trace(MMS_DEVP, "when");
	arg = mms_pn_lookup(cmd->cmd_root, "when",
	    MMS_PN_CLAUSE, NULL);
	if (arg != NULL) {
		MMS_PN_LOOKUP(value,
		    arg, NULL, MMS_PN_KEYWORD, NULL);
		if (strcmp(value->pn_string, "blocking") == 0) {
			mount_info->cmi_when = MM_BLOCKING;
		} else {
			mount_info->cmi_when = MM_IMMEDIATE;
		}
	} else {
		/* when is optional and defaults to immediate */
		mount_info->cmi_when = MM_IMMEDIATE;
	}

	/* Get where */
	mms_trace(MMS_DEVP, "where");
	work = NULL;
	arg = mms_pn_lookup(cmd->cmd_root, "where",
	    MMS_PN_CLAUSE, &work);
	if (arg != NULL) {
		MMS_PN_LOOKUP(value, arg, NULL,
		    MMS_PN_STRING, NULL);
		if (value->pn_string != NULL) {
			dm_host = value->pn_string;
		} else {
			dm_host = mm_cci_host_ident(conn);
		}
	} else {
		mms_trace(MMS_DEVP, "Didn't find a where clause...");
		dm_host = mm_cci_host_ident(conn);
	}
	mount_info->cmi_where = mm_host_ident(dm_host);
	mms_trace(MMS_DEVP, "where %s", mount_info->cmi_where);

	/* Get File Name - Optional */
	mms_trace(MMS_DEVP, "filename");
	work = NULL;
	arg = mms_pn_lookup(cmd->cmd_root, "filename",
	    MMS_PN_CLAUSE, &work);
	if (arg != NULL) {
		MMS_PN_LOOKUP(value, arg, NULL,
		    MMS_PN_STRING, NULL);
		if (value->pn_string != NULL) {
			mount_info->cmi_filename =
			    strdup(value->pn_string);
		} else {
			mount_info->cmi_filename = NULL;
		}
	} else {
		mms_trace(MMS_DEVP, "Didn't find a filename clause...");
		mount_info->cmi_filename = NULL;
	}
	/* Get BlockSize - Optional */
	mms_trace(MMS_DEVP, "blocksize");
	work = NULL;
	arg = mms_pn_lookup(cmd->cmd_root, "blocksize",
	    MMS_PN_CLAUSE, &work);
	if (arg != NULL) {
		MMS_PN_LOOKUP(value, arg, NULL,
		    MMS_PN_STRING, NULL);
		if (value->pn_string != NULL) {
			mount_info->cmi_blocksize =
			    strdup(value->pn_string);
		} else {
			mount_info->cmi_blocksize = NULL;
		}
	} else {
		mms_trace(MMS_DEVP, "Didn't find a blocksize clause...");
		mount_info->cmi_blocksize = NULL;
	}
	/* Get volumeid - Optional */
	mms_trace(MMS_DEVP, "volumeid");
	work = NULL;
	arg = mms_pn_lookup(cmd->cmd_root, "volumeid",
	    MMS_PN_CLAUSE, &work);
	if (arg != NULL) {
		MMS_PN_LOOKUP(value, arg, NULL,
		    MMS_PN_STRING, NULL);
		if (value->pn_string != NULL) {
			mount_info->cmi_volumeid =
			    strdup(value->pn_string);
		} else {
			mount_info->cmi_volumeid = NULL;
		}
	} else {
		mms_trace(MMS_DEVP, "Didn't find a volumeid clause...");
		mount_info->cmi_volumeid = NULL;
	}
	/* Get filesequence - Optional */
	mms_trace(MMS_DEVP, "filesequence");
	work = NULL;
	arg = mms_pn_lookup(cmd->cmd_root, "filesequence",
	    MMS_PN_CLAUSE, &work);
	if (arg != NULL) {
		MMS_PN_LOOKUP(value, arg, NULL,
		    MMS_PN_STRING, NULL);
		if (value->pn_string != NULL) {
			mount_info->cmi_filesequence =
			    strdup(value->pn_string);
		} else {
			mount_info->cmi_filesequence = NULL;
		}
	} else {
		mms_trace(MMS_DEVP, "Didn't find a filesequence clause...");
		mount_info->cmi_filesequence = NULL;
	}
	/* Get user - Optional */
	mms_trace(MMS_DEVP, "user");
	work = NULL;
	arg = mms_pn_lookup(cmd->cmd_root, "user",
	    MMS_PN_CLAUSE, &work);
	if (arg != NULL) {
		MMS_PN_LOOKUP(value, arg, NULL,
		    MMS_PN_STRING, NULL);
		if (value->pn_string != NULL) {
			mount_info->cmi_user =
			    strdup(value->pn_string);
		} else {
			mount_info->cmi_user = NULL;
		}
	} else {
		mms_trace(MMS_DEVP, "Didn't find a user clause...");
		mount_info->cmi_user = NULL;
	}

	/* Get First Mount Clause */
	mms_trace(MMS_DEVP, "firstmount");
	work = NULL;
	arg = mms_pn_lookup(cmd->cmd_root, "firstmount",
	    MMS_PN_CLAUSE, &work);
	item = NULL;
	if (arg != NULL) {
		count = 0;
		go = 1;
		while (go) {

			if ((value =
			    mms_pn_lookup(arg, NULL,
			    MMS_PN_STRING,
			    &item)) == NULL) {
				go = 0;
			} else {
				mount_info->cmi_firstmount[count] =
				    value->pn_string;
				count ++;
			}

		}
		mount_info->cmi_num_firstmount = count;
	} else {
		mms_trace(MMS_DEVP, "Didin't find a first mount clause");
	}

	/* Get Access Mode Clause */
	mms_trace(MMS_DEVP, "accessmode");

	work = NULL;
	for (arg = mms_pn_lookup(cmd->cmd_root, "accessmode",
	    MMS_PN_CLAUSE, &work);
	    arg != NULL;
	    arg = mms_pn_lookup(cmd->cmd_root, "accessmode",
	    MMS_PN_CLAUSE, &work)) {
		/* Malloc a new mode object */
		mode = (cmi_mode_list_t *)
		    calloc(1, sizeof (cmi_mode_list_t));
		if (mode == NULL) {
			mms_trace(MMS_ERR,
			    "Unable to malloc cmi_mode_list: %s",
			    strerror(errno));
			mm_system_error(cmd,
			    "unable to allocate "
			    "memory for mode list");
			return (MM_CMD_ERROR);
		}
		/* Get all of the access Mode tokens */
		item = NULL;
		count = 0;
		go = 1;
		while (go) {
			if ((value =
			    mms_pn_lookup(arg, NULL,
			    MMS_PN_STRING,
			    &item)) == NULL) {
				go = 0;
			} else {
				mode->cmi_accessmode[count] =
				    value->pn_string;
				count ++;
			}
		}
		/* Put this access mode into the Accessmode list */
		mount_info->cmi_total_modes ++;
		mode->cmi_num_accessmode = count;
		mms_list_insert_tail(&mount_info->cmi_mode_list, mode);
	}

	/* Get retention clause */
	/* Get user - Optional */
	mms_trace(MMS_DEVP, "retention");
	work = NULL;
	arg = mms_pn_lookup(cmd->cmd_root, "retention",
	    MMS_PN_CLAUSE, &work);
	if (arg != NULL) {
		MMS_PN_LOOKUP(value, arg, NULL,
		    MMS_PN_STRING, NULL);
		if (value->pn_string != NULL) {
			mount_info->cmi_retention =
			    strdup(value->pn_string);
		} else {
			mount_info->cmi_retention = NULL;
		}
	} else {
		mms_trace(MMS_DEVP, "Didn't find a retention clause");
		mount_info->cmi_retention = NULL;
	}
	return (MM_CMD_DONE);


not_found:
	mm_response_error(cmd,
	    ECLASS_LANGUAGE,
	    ENOTFOUND,
	    MM_5062_MSG,
	    NULL);
	cmd->cmd_remove = 1;
	mm_send_text(mm_wka->mm_wka_conn, cmd->cmd_buf);
	return (MM_CMD_ERROR);
no_mem:
	MM_ABORT_NO_MEM();
	return (MM_CMD_ERROR);

}


void
mm_mount_clean_candidates(mm_command_t *cmd) {
	cmd_mount_info_t	*mount_info = &cmd->cmd_mount_info;
	cmi_cart_list_t		*cart = NULL;
	cmi_drive_list_t	*drive = NULL;

	int			has_drive = 0;


	cmi_cart_list_t *next_cart;

	cmi_drive_list_t *next_drive;


	mms_trace(MMS_DEVP, "mm_mount_clean_candidates");


	/* Cannot use mms_list_foreach when removing list elements */
	/* For each cart */
	for (cart = mms_list_head(&mount_info->
	    cmi_cart_list);
	    cart != NULL;
	    cart = next_cart) {
		next_cart =
		    mms_list_next(&mount_info->
		    cmi_cart_list,
		    cart);

		mms_trace(MMS_DEVP, "  check cart %s",
		    cart->cmi_cart_pcl);
		has_drive = 0;

		/* For each drive */
		for (drive = mms_list_head(&cart->
		    cmi_drive_list);
		    drive != NULL;
		    drive = next_drive) {
			next_drive =
			    mms_list_next(&cart->
			    cmi_drive_list,
			    drive);

			mms_trace(MMS_DEVP, "    check drive %s",
			    drive->cmi_drive_name);
			if (drive->cmi_remove_drive) {
				mms_list_remove(&cart->
				    cmi_drive_list,
				    drive);
				mms_trace(MMS_DEVP,
				    "      free drive %s",
				    drive->cmi_drive_name);
				mm_free_cmi_drive(drive);
			} else {
				mms_trace(MMS_DEVP,
				    "      drive good, %s",
				    drive->cmi_drive_name);
				has_drive = 1;
			}
		}
		if (has_drive == 0)
			cart->cmi_remove_cart = 1;
		if (cart->cmi_remove_cart) {
			mms_list_remove(&mount_info->cmi_cart_list, cart);
			mms_trace(MMS_DEVP,
			    "  free cart, %s",
			    cart->cmi_cart_pcl);
			mm_free_cmi_cart(cart);
		} else {
			mms_trace(MMS_DEVP,
			    "  cart good, %s",
			    cart->cmi_cart_pcl);
		}
	}

}

int
mm_mount_check_candidates(mm_wka_t *mm_wka, mm_command_t *cmd,
    mm_db_t *db) {
	cmd_mount_info_t	*mount_info = &cmd->cmd_mount_info;
	cmi_cart_list_t		*cart = NULL;
	cmi_drive_list_t	*drive = NULL;

	char			*candidate_cartid = NULL;
	char			*candidate_drive = NULL;

	mms_list_foreach(&mount_info->cmi_cart_list, cart) {

		candidate_cartid = cart->cmi_cart_id;

		mms_trace(MMS_INFO, "Check Cartridge, %s",
		    candidate_cartid);

		if (mm_candidate_cartridge_ok(mm_wka,
		    cmd, db,
		    cart)) {
			/* Cartridge is ok */
			if (cart->cmi_cart_not_ready) {
				mms_trace(MMS_DEVP,
				    "cartridge %s is not "
				    "ready/in use",
				    candidate_cartid);
			} else {
				mms_trace(MMS_DEVP,
				    "Cartridge, %s, is available",
				    candidate_cartid);
			}
		} else {
			/* Cartridge not available */
			mms_trace(MMS_DEVP,
			    "Cartridge, %s, is not "
			    "available for mount",
			    candidate_cartid);
			cart->cmi_remove_cart = 1;
			/* Go on to next cartridge */
			continue;
		}


		mms_list_foreach(&cart->cmi_drive_list, drive) {

			candidate_drive = drive->cmi_drive_name;
			if (cart->cmi_cart_not_ready) {
				drive->cmi_drive_not_ready = 1;
				continue;
			}

			mms_trace(MMS_INFO,
			    "Check Drive, %s", candidate_drive);
			if (mm_candidate_drive_ok(mm_wka,
			    cmd, db,
			    candidate_cartid,
			    drive)) {
				if (drive->cmi_drive_not_ready) {
					mms_trace(MMS_DEVP,
					    "Drive, %s, is not ready/in use",
					    candidate_drive);
				} else {
					mms_trace(MMS_DEVP,
					    "Drive, %s, is available",
					    candidate_drive);
				}
			} else {
				mms_trace(MMS_DEVP,
				    "Drive, %s, not available"
				    " for mounts",
				    candidate_drive);
				drive->cmi_remove_drive = 1;
			}
		}
	}

	mm_mount_clean_candidates(cmd);
	return (0);
}

int
mm_mount_init_candidates(mm_command_t *cmd,
    PGresult *cart_results, mm_db_t *db) {
	cmd_mount_info_t	*mount_info = &cmd->cmd_mount_info;


	cmi_cart_list_t		*cur_cart;


	int			cart_rows;
	int			cart_row;
	int			drive_rows;
	int			drive_row;

	char			*candidate_library = NULL;
	char			*candidate_drive = NULL;
	char			*candidate_cartid = NULL;



	PGresult		*drive_results;

	cart_rows = PQntuples(cart_results);
	mm_free_cmi_cart_list(&mount_info->cmi_cart_list);

	for (cart_row = 0; cart_row < cart_rows; cart_row ++) {
		candidate_cartid = PQgetvalue(cart_results, cart_row, 0);
		candidate_library = PQgetvalue(cart_results, cart_row, 1);
		mms_trace(MMS_DEVP,
		    "mm_mount_init_candidates: cartid = %s, library = %s",
		    candidate_cartid, candidate_library);

		/* Allocate this cartridge */
		cur_cart = NULL;
		cur_cart = mm_setup_cart(cmd,
		    db,
		    cart_results,
		    cart_row);
		if (cur_cart == NULL) {
			mms_trace(MMS_ERR, "error allocing candidate cart");
			mm_system_error(cmd,
			    "error allocing candidate cart");
			return (1);
		}
		mms_trace(MMS_INFO, "Check Library, %s",
		    candidate_library);
		if (mm_candidate_library_ok(cmd, db,
		    candidate_library)) {
			mms_trace(MMS_DEVP,
			    "Library, %s, is available",
			    candidate_library);
		} else {
			mms_trace(MMS_DEVP,
			    "Library, %s, not available",
			    candidate_library);
			cur_cart->cmi_remove_cart = 1;
			/* Go on to next cartridge */
			continue;
		}


		/* Get the drives in this library */
		/* Do some ordering of drives here */
		/* mm_mount_order_candidates will do the ordering */
		if (cmd->cmd_func == mm_mount_cmd_func) {
			if (mm_db_exec(HERE, db,
			    "select distinct \"DriveName\","
			    "\"LibraryName\",\"DrivePriority\","
			    "\"DriveNumberMounts\" from ("
			    "select \"DriveName\",\"LibraryName\","
			    "\"DrivePriority\",\"DriveNumberMounts\""
			    "from \"DRIVE\""
			    "where (\"DRIVE\".\"LibraryName\" = '%s')"
			    "order by \"DRIVE\".\"DriveNumberMounts\""
			    ") as foo order by \"DrivePriority\";",
			    candidate_library) != MM_DB_DATA) {
				mms_trace(MMS_ERR,
				    "db error, init candidate cart");
				mm_sql_db_err_rsp_new(cmd, db);
				return (1);
			}
		} else {
			if (mm_db_exec(HERE, db,
			    "select distinct \"DriveName\","
			    "\"LibraryName\",\"DrivePriority\","
			    "\"DriveNumberMounts\" from ("
			    "select \"DriveName\",\"LibraryName\","
			    "\"DrivePriority\",\"DriveNumberMounts\""
			    "from \"DRIVE\""
			    "where (\"DRIVE\".\"LibraryName\" = '%s' "
			    "and \"DRIVE\".\"CartridgePCL\" = '%s')"
			    "order by \"DRIVE\".\"DriveNumberMounts\""
			    ") as foo order by \"DrivePriority\";",
			    candidate_library,
			    cur_cart->cmi_cart_pcl) != MM_DB_DATA) {
				mms_trace(MMS_ERR,
				    "db error, init candidate cart");
				mm_sql_db_err_rsp_new(cmd, db);
				return (1);
			}
		}
		drive_results = db->mm_db_results;
		drive_rows = PQntuples(drive_results);
		if (drive_rows == 0) {
			mms_trace(MMS_ERR,
			    "couldn't match any drives for library %s",
			    candidate_library);
			mm_response_error(cmd,
			    ECLASS_EXPLICIT, ENOMATCH,
			    MM_5094_MSG,
			    "lib",
			    candidate_library,
			    NULL);
			mm_clear_db(&drive_results);
			return (1);
		}

		for (drive_row = 0; drive_row < drive_rows; drive_row ++) {

			candidate_drive = PQgetvalue(drive_results,
			    drive_row, 0);

			mms_trace(MMS_DEVP,
			    "mm_mount_init_candidates: drive = %s",
			    candidate_drive);

			/* mm_set_dirve_unmount and */
			/* mm_setup_drive return a pointer */
			/* to the set up drive struct */
			if (mount_info->cmi_operation == MM_UNMOUNT) {
				(void) mm_setup_drive_unmount(cmd,
				    db,
				    cur_cart,
				    drive_results,
				    drive_row);
			} else {
				(void) mm_setup_drive(cmd,
				    db,
				    cur_cart,
				    drive_results,
				    drive_row);
			}

		}
		mm_clear_db(&drive_results);
	}

	mm_mount_clean_candidates(cmd);
	return (0);

}


PGresult* mm_mount_cart_results(mm_wka_t *mm_wka,
    mm_command_t *cmd, mm_db_t *db) {
	cmd_mount_info_t	*mount_info = &cmd->cmd_mount_info;
	char			*path_buf = NULL;
	char			*tmp_buf = NULL;

	cci_t			*conn = &mm_wka->wka_conn;
	char			*app_name = conn->cci_client;
	int			i;


	mm_clear_source(cmd);
	mm_clear_dest(cmd);
	mm_clear_const(cmd);

	if (mm_get_dest(mm_wka, cmd)) {
		/* Command does not have a match/volname clause */
		mms_trace(MMS_DEVP, "No match/volname Clause???");
	} else {
		/* TEMP - Trace out our dest info */
		mms_trace(MMS_DEVP, "Dest count is %d", cmd->cmd_dest_num);
		mm_print_char_list(&cmd->cmd_dest_list);
	}

	if (mm_get_const(mm_wka, cmd)) {
		/* Command does not have a match/volname clause */
		mms_trace(MMS_DEVP, "No match/volname Clause???");
	} else {
		/* TEMP - Trace out our const info */
		mms_trace(MMS_DEVP, "Const count is %d", cmd->cmd_const_num);
		mm_print_char_list(&cmd->cmd_const_list);
	}

	if (cmd->wka_ptr->wka_privilege == MM_PRIV_STANDARD) {
		/* add CARTRIDGEGROUPAPPLICATION constraint */
		(void) mm_add_to_dest(cmd,
		    "CARTRIDGEGROUPAPPLICATION");
		if (tmp_buf)
			free(tmp_buf);
		tmp_buf = NULL;
		tmp_buf = mms_strapp(tmp_buf,
		    "\"CARTRIDGEGROUPAPPLICATION\"."
		    "\"ApplicationName\" = '%s'",
		    app_name);
		(void) mm_add_to_const(cmd, tmp_buf);
		if (tmp_buf)
			free(tmp_buf);
		tmp_buf = NULL;
	}

	/* Clear cmd_buf */
	if (cmd->cmd_buf)
		SQL_CHK_LEN(&cmd->cmd_buf, NULL,
		    &cmd->cmd_bufsize, 0);


	/* Make path_buf and set source */
	path_buf = mms_strapp(path_buf,
	    "select distinct");
	if (mount_info->cmi_type == MM_VOLUME) {

		if (mm_add_char("VOLUME",
		    &cmd->cmd_source_list)) {
			mms_trace(MMS_ERR,
			    "mm_mount_cart_results: "
			    "Error adding char to source list");
			mm_system_error(cmd,
			    "out of mem adding to source list");
			return (NULL);
		}
		path_buf = mms_strapp(path_buf,
		    "\"VOLUME\"");

	}
	if (mount_info->cmi_type == MM_PARTITION) {
		if (mm_add_char("PARTITION",
		    &cmd->cmd_source_list)) {
			mms_trace(MMS_ERR,
			    "mm_mount_cart_results: "
			    "Error adding char to source list");
			mm_system_error(cmd,
			    "out of mem adding to source list");
			return (NULL);
		}
		path_buf = mms_strapp(path_buf,
		    "\"PARTITION\"");
	}
	if (mount_info->cmi_type == MM_SIDE) {
		if (mm_add_char("SIDE",
		    &cmd->cmd_source_list)) {
			mms_trace(MMS_ERR,
			    "mm_mount_cart_results: "
			    "Error adding char to source list");
			mm_system_error(cmd,
			    "out of mem adding to source list");
			return (NULL);
		}
		path_buf = mms_strapp(path_buf,
		    "\"SIDE\"");
	}
	if (tmp_buf != NULL) {
		free(tmp_buf);
		tmp_buf = NULL;
	}


	/* Put path_buf into cmd_buf */
	path_buf = mms_strapp(path_buf,
	    ".\"CartridgeID\" from\n");
	SQL_CHK_LEN(&cmd->cmd_buf, NULL,
	    &cmd->cmd_bufsize, strlen(path_buf) + 1);
	strcpy(cmd->cmd_buf, path_buf);
	free(path_buf);
	path_buf = NULL;
	cmd->cmd_source_num = 1;
	/* Make report funcs */

	if (mm_sql_from_where(cmd, db)) {
		mms_trace(MMS_ERR,
		    "mm_mount_cart_results: "
		    "db error creating helper functions");
		return (NULL);
	}

	if (mm_db_exec(HERE, db, cmd->cmd_buf) != MM_DB_DATA) {
		mm_sql_db_err_rsp_new(cmd, db);
		mms_trace(MMS_ERR,
		    "db error getting candidate cartridges");
		return (NULL);
	}

	if (PQntuples(db->mm_db_results) == 0) {
		/* no cartridge matches */
		mms_trace(MMS_INFO,
		    "match statment in mount "
		    "didn't match any cartridge/volumes");
		mm_response_error(cmd,
		    ECLASS_EXPLICIT, ENOMATCH,
		    MM_5052_MSG,
		    NULL);
		mm_clear_db(&db->mm_db_results);
		return (NULL);
	}


	/* Order cartridges based on priority and last time mounted */
	/* Additional Cartridge Ordering */
	/* done in mm_mount_order_candidates */
	tmp_buf = mms_strapp(tmp_buf,
	    "select distinct \"CartridgeID\","
	    "\"LibraryName\",\"CartridgeGroupPriority\","
	    "\"CartridgeNumberMounts\", "
	    "\"CartridgeShapeName\",\"CartridgePCL\", "
	    "\"CartridgeDriveOccupied\" "
	    "from ( "
	    "select \"CartridgeID\",\"LibraryName\", "
	    "\"CartridgeGroupPriority\","
	    "\"CartridgeNumberMounts\", "
	    "\"CartridgeShapeName\",\"CartridgePCL\", "
	    "\"CartridgeDriveOccupied\" "
	    "from \"CARTRIDGE\","
	    "\"CARTRIDGEGROUP\",\"CARTRIDGETYPE\" ");
	for (i = 0; i < PQntuples(db->mm_db_results); i++) {
		if (i == 0) {
			tmp_buf = mms_strapp(tmp_buf, "where (");
		} else {
			tmp_buf = mms_strapp(tmp_buf, "or ");
		}
		tmp_buf = mms_strapp(tmp_buf, " (\"CartridgeID\" = '%s')",
		    PQgetvalue(db->mm_db_results, i, 0));
	}
	tmp_buf = mms_strapp(tmp_buf,
	    ") and"
	    "(\"CARTRIDGEGROUP\".\"CartridgeGroupName\" "
	    "= \"CARTRIDGE\".\"CartridgeGroupName\")"
	    "and"
	    "(\"CARTRIDGE\".\"CartridgeTypeName\" "
	    "= \"CARTRIDGETYPE\".\"CartridgeTypeName\")"
	    "order by \"CARTRIDGE\".\"CartridgeTimeMountedLast\""
	    ") as foo order by \"CartridgeGroupPriority\";");
	mm_clear_db(&db->mm_db_results);
	if (mm_db_exec(HERE, db, tmp_buf) != MM_DB_DATA) {
		free(tmp_buf);
		mm_sql_db_err_rsp_new(cmd, db);
		return (NULL);
	}
	free(tmp_buf);
	return (db->mm_db_results);
no_mem:
	MM_ABORT_NO_MEM();
	return (NULL);

}

int
mm_mount_ready(mm_wka_t *mm_wka, mm_command_t *cmd, mm_db_t *db, int is_retry) {

	cmd_mount_info_t	*mount_info = &cmd->cmd_mount_info;


	PGresult		*cart_results;
	int			cart_rows;

	cmi_cart_list_t		*cart = NULL;
	cmi_drive_list_t	*drive = NULL;


	int			found_cart_drive = 0;
	int			found_ready_cart_drive = 0;

	int			rc;

	int			resync_tries = 5;
	int			i = 0;

	/* Do drive/cart/lib selection using path matching */
	if ((cart_results = mm_mount_cart_results(mm_wka,
	    cmd, db)) == NULL) {
		/* No carts or error */
		return (MM_MOUNT_ERROR);
	}

	cart_rows = PQntuples(cart_results);
	mms_trace(MMS_DEVP, "Number of Cartridges is %d", cart_rows);

	if (cart_rows == 0) {
		/* No Cartridge Matches Error */
		mms_trace(MMS_INFO,
		    "match statment in mount "
		    "didn't match any cartridge/volumes");
		mm_response_error(cmd,
		    ECLASS_EXPLICIT, ENOMATCH,
		    MM_5052_MSG,
		    NULL);
		mm_clear_db(&cart_results);
		return (MM_MOUNT_ERROR);
	}
	/* Create the list objects for */
	/* every cartridge/drive candidate */
	if (mm_mount_init_candidates(cmd, cart_results,
	    db)) {
		mms_trace(MMS_ERR,
		    "error initializing candidate lists");
		/* err buf should be set by mm_mount_init */
		/* so return and remove */
		mm_clear_db(&cart_results);
		return (MM_MOUNT_ERROR);
	}
	mms_trace(MMS_DEVP, "candidate list created, check availability ");
	mm_clear_db(&cart_results);
	/* Check the availability of the candidates */
	if (mm_mount_check_candidates(mm_wka, cmd,
	    db)) {
		mms_trace(MMS_ERR,
		    "error checking candidate lists");
		mm_system_error(cmd,
		    "error checking candidate lists");
		return (MM_MOUNT_ERROR);
	}
	mms_trace(MMS_DEVP, "done checking list");



	/* Print mount information */
	mm_print_mount_summary(mm_wka, cmd);


	/*
	 * For blocking mounts,
	 * check that at least some cart/drive combo exists
	 * if that cart/drive exists, but is not ready, return not ready
	 *
	 * for immediate mounts, check that at least one combination exists
	 */

	found_cart_drive = 0;
	found_ready_cart_drive = 0;

	/* if cart/drive is not reay, set for remove */
	mms_list_foreach(&mount_info->cmi_cart_list, cart) {
		if (cart->cmi_cart_not_ready)
			cart->cmi_remove_cart = 1;
		mms_list_foreach(&cart->cmi_drive_list, drive) {
			found_cart_drive = 1;
			if ((cart->cmi_cart_not_ready == 0) &&
			    (drive->cmi_drive_not_ready == 0)) {
				found_ready_cart_drive = 1;
			}
			if (drive->cmi_drive_not_ready)
				drive->cmi_remove_drive = 1;
		}
	}


	/* If there is a library or drive error */
	/* the error buff has already been set */
	if (found_cart_drive == 0) {
		mms_trace(MMS_INFO,
		    "No candidate "
		    "cartridge/library/drive "
		    "combination found");
		/* set least severe error */
		mm_set_least_severe(cmd);
		return (MM_MOUNT_ERROR);
	}
	if (found_ready_cart_drive == 0) {
		mms_trace(MMS_INFO,
		    "candidate "
		    "cartridge/library/drive "
		    "combination found, but is not ready");
		return (MM_MOUNT_NOT_READY);
	}
	/* There is a ready cart/drive */
	/* we may have set some non ready for remove */
	/* so call the clean func before contine */
	mm_mount_clean_candidates(cmd);
	cmd->cmd_state = 1;
	rc = mm_set_immediate_mount(mm_wka, cmd, db);

	if (rc == MM_RESYNC) {
		if (is_retry) {
			return (rc);
		}
		/* Destroy all cart lists */
		mms_trace(MMS_INFO,
		    "mm_mount_ready: "
		    "states out of sync, attempt to resync this mount");
		for (i = 0; i < resync_tries; i++) {
			mm_free_cmi_cart_list(&mount_info->cmi_cart_list);
			rc = mm_mount_ready(mm_wka, cmd, db, 1);
			if (rc != MM_RESYNC) {
				mms_trace(MMS_INFO,
				    "mm_mount_ready: "
				    "resync successful");
				return (rc);
			}
		}
		mms_trace(MMS_INFO,
		    "mm_mount_ready: "
		    "states out of sync, resync failed");
		return (MM_MOUNT_ERROR);
	}
	if (rc == MM_CMD_ERROR) {
		mms_trace(MMS_ERR,
		    "error setting up immediate mount");
		/* set least severe error */
		mm_set_least_severe(cmd);
		return (MM_MOUNT_ERROR);
	} else if (rc == MM_DISPATCH_DEPEND) {
		/* this immediate mount needs to */
		/* wait for an unload */
		mms_trace(MMS_DEVP,
		    " mount waiting "
		    "for unload to complete");
		return (MM_MOUNT_NEED_UNLOAD);
	}
	mms_trace(MMS_DEVP,
	    "mount ready for dispatch");

	return (MM_MOUNT_READY);

db_error:
	mm_sql_db_err_rsp_new(cmd, db);
	return (MM_MOUNT_ERROR);

}


int
mm_mount_cmd_func(mm_wka_t *mm_wka, mm_command_t *cmd)
{

	mm_db_t			*db = &mm_wka->mm_data->mm_db;
	cci_t			*conn = &mm_wka->wka_conn;
	cmd_mount_info_t	*mount_info = &cmd->cmd_mount_info;

	int			rows;
	int			rc;
	char			*response_message = NULL;
	mm_command_t		*dmp_release = NULL;

	mms_trace(MMS_DEVP, "mm mount cmd state %d", cmd->cmd_state);

	if (cmd->cmd_state == 0) {

		mms_trace(MMS_INFO, "Processing Mount Request...");
		/*
		 * Generate Candidate Cartridge and Drive lists
		 * First parse and save the mount info
		 * then use SQL queries to gereate the lists
		 */

		mount_info->cmi_mount_cart_loaded = 0;
		mount_info->cmi_fail_type = NONE;
		if (mm_parse_mount_cmd(mm_wka, cmd) == MM_CMD_ERROR) {
			mms_trace(MMS_ERR,
			    "error parsing mount command");
			/* Error buf should already be set */
			cmd->cmd_remove = 1;
			mm_send_text(mm_wka->mm_wka_conn, cmd->cmd_buf);
			return (MM_CMD_ERROR);
		}
		mms_trace(MMS_DEVP, "done parsing");



		/* ***DONE PARSING MOUNT COMMAND*** */

		if (mount_info->cmi_when == MM_BLOCKING) {
			if (mm_set_tm_task(db, cmd) != MM_DB_OK) {
				goto db_error;
			}
			mms_trace(MMS_DEVP,
			    "blocking mount will be passed to task manager");
			return (MM_WORK_TODO);
		}
		/* This is an immediate mount */
		rc = mm_mount_ready(mm_wka, cmd, db, 0);
		switch (rc) {

		case MM_MOUNT_ERROR:
			/* Error code should be set */
			mms_trace(MMS_ERR,
			    "internal error, mm_mount_ready");
			cmd->cmd_remove = 1;
			mm_send_text(mm_wka->mm_wka_conn, cmd->cmd_buf);
			return (MM_CMD_ERROR);

		case MM_MOUNT_READY:
			/* The mount is ready, mount_info should be set */
			/* continue to state 1 */
			cmd->cmd_state = 1;
			mms_trace(MMS_DEVP,
			    "mount is ready to go, "
			    "continue to state 1");
			break;

		case MM_MOUNT_NEED_UNLOAD:
			/* this immediate mount needs to */
			/* wait for an unload */
			cmd->cmd_state = 1;
			mms_trace(MMS_DEVP,
			    "mount waiting "
			    "for unload to complete");
			return (MM_DISPATCH_DEPEND);

		case MM_MOUNT_NOT_READY:
			/* Error code should be set */
			mms_trace(MMS_ERR,
			    "immediate mount not ready, "
			    "send error to client");
			cmd->cmd_remove = 1;
			mm_send_text(mm_wka->mm_wka_conn, cmd->cmd_buf);
			return (MM_CMD_ERROR);

		default:
			mms_trace(MMS_ERR,
			    "bad rc mm_mount_ready");
			mm_system_error(cmd,
			    "bad rc mm_mount_ready");
			cmd->cmd_remove = 1;
			mm_send_text(mm_wka->mm_wka_conn, cmd->cmd_buf);
			return (MM_CMD_ERROR);

		}
	}

start:
	if (cmd->cmd_state == 1) {
		mms_trace(MMS_INFO, "Mounting tape...");

		/* Reserve the DM */
		/*
		 * mm_sql_update_state(mm_wka->mm_data, "DM",
		 *   "DMStateSoft",
		 *   "reserved", "DMName",
		 *   mount_info->cmi_dm);
		 */
		mm_sql_update_state(mm_wka->mm_data, "DRIVE",
		    "DMName",
		    mount_info->cmi_dm, "DriveName",
		    mount_info->cmi_drive);

		/*  Add activate command */
		if (mm_dmp_add_cmd(mm_wka, cmd, mount_info->cmi_dm,
		    MM_DMP_RESERVE) == NULL) {
			mms_trace(MMS_ERR,
			    "error adding dmp reserve");
			mm_system_error(cmd,
			    "error adding dmp reserve");
			goto reset_states;
		}
		cmd->cmd_state = 3;
		return (MM_DISPATCH_DEPEND);
	} else if (cmd->cmd_state == 3) {

		/*
		 * Mount cartridge in the library drive
		 */

		mm_command_t		*lmp_mnt_cmd;
		mm_wka_t		*lm_wka;
		uuid_text_t		 new_task;
		char			*cart_pcl;
		char			*side_name;

		/*
		 * DM Activate failed
		 */
		if (cmd->cmd_flags & MM_CMD_DEPEND_ERROR) {
			mms_trace(MMS_DEVP, "DM reserve failed");
			/* Reset drive and cartridge */
			/* return error to client */
			mount_info->cmi_reset_states = 1;
			goto lm_dm_error;
		}

		if (mount_info->cmi_mount_cart_loaded) {
			/* Skip lmp mount */
			cmd->cmd_state = 4;
			goto start;
		}
		/*
		 * Cartridge pcl and side name
		 */
		if ((cart_pcl = mm_get_cart_pcl(cmd,
		    cmd->cmd_mount_info.cmi_cartridge, db)) == NULL) {
			/* Error buf should be set in mm_get_cart_pcl */
			goto reset_states;
		}

		/* TODO side name needs to be generated in candidate query */
		if ((side_name = cmd->cmd_mount_info.cmi_side_name) == NULL) {
			side_name = "side 1";
		}

		/*
		 * LMP mount command
		 */
		lm_wka = mm_library_lm_wka(cmd->wka_ptr->mm_data,
		    cmd->cmd_mount_info.cmi_library, NULL);
		if ((lmp_mnt_cmd = mm_alloc_cmd(lm_wka)) == NULL) {
			mms_trace(MMS_ERR,
			    "Unable to malloc mm_command_t: %s",
			    strerror(errno));
			mm_system_error(cmd,
			    "Unable to malloc lmp mount cmd");
			goto reset_states;
		}

		lmp_mnt_cmd->cmd_func = mm_lmp_mount_cmd_func;
		mm_get_uuid(new_task);
		lmp_mnt_cmd->cmd_textcmd = mms_strnew(LMP_MOUNT, new_task,
		    cart_pcl, cart_pcl, side_name,
		    cmd->cmd_mount_info.cmi_drive);
		lmp_mnt_cmd->cmd_root =
		    mm_text_to_par_node(lmp_mnt_cmd->cmd_textcmd,
		    mms_lmpm_parse);
		lmp_mnt_cmd->cmd_task = mm_get_task(lmp_mnt_cmd->cmd_root);
		mm_add_depend(lmp_mnt_cmd, cmd);
		lmp_mnt_cmd->cmd_name = strdup("lmp mount");
		lmp_mnt_cmd->cmd_mount_info.cmi_drive =
		    strdup(cmd->cmd_mount_info.cmi_drive);
		lmp_mnt_cmd->cmd_mount_info.cmi_cartridge =
		    strdup(cmd->cmd_mount_info.cmi_cartridge);
		cmd->cmd_state = 4;

		pthread_mutex_lock(&mm_wka->mm_data->mm_queue_mutex);
		mms_list_insert_tail(&mm_wka->mm_data->mm_cmd_queue,
		    lmp_mnt_cmd);
		pthread_mutex_unlock(&mm_wka->mm_data->mm_queue_mutex);

		free(cart_pcl);

		return (MM_DISPATCH_DEPEND);

	} else if (cmd->cmd_state == 4) {

		/*
		 * LMP Mount command failed
		 */
		if (cmd->cmd_flags & MM_CMD_DEPEND_ERROR) {
			mms_trace(MMS_DEVP, "lm mount failed");
			/* Reset drive and cartridge */
			/* return error to client */
			mount_info->cmi_reset_states = 1;
			mount_info->cmi_need_clear = 1;
			/* DM is reserved, release the DM */
			if (dmp_release = mm_dmp_add_cmd(mm_wka,
			    cmd, mount_info->cmi_dm,
			    MM_DMP_RELEASE)) {
				/* run withtout parent */
				mm_remove_all_depend(dmp_release);
			}
			/* Generate error message */
			response_message =
			    mm_ret_response_msg(cmd);
			mm_response_error(cmd,
			    "subop", "ELMPMOUNT", MM_5018_MSG,
			    "cartridge", mount_info->cmi_cartridge,
			    "drive", mount_info->cmi_drive,
			    "msg_rsp", response_message,
			    NULL);
			free(response_message);
			/* Set cmd for remove, send message to client */
			cmd->cmd_remove = 1;
			mm_send_text(mm_wka->mm_wka_conn,
			    cmd->cmd_buf);
			rc = MM_CMD_ERROR;
			goto end;
		}
		if (mm_dmp_add_cmd(mm_wka, cmd, mount_info->cmi_dm,
		    MM_DMP_PRIV) == NULL) {
			mms_trace(MMS_ERR,
			    "error adding dmp private");
			mm_system_error(cmd,
			    "error adding dmp private");
			goto reset_states;
		}
		cmd->cmd_state = 5;
		return (MM_DISPATCH_DEPEND);
	} else if (cmd->cmd_state == 5) {

		/* DM_load state */
		/*
		 * Private has finished, add a load command to the
		 * queue
		 */
		if (cmd->cmd_flags & MM_CMD_DEPEND_ERROR) {
			mms_trace(MMS_DEVP, "mmp_mount-> DMP private error");
			/* Reset drive and cartridge */
			/* return error to client */
			mount_info->cmi_reset_states = 1;
			mount_info->cmi_need_clear = 1;
			/* DM is reserved, release the DM */
			if (dmp_release = mm_dmp_add_cmd(mm_wka,
			    cmd, mount_info->cmi_dm,
			    MM_DMP_RELEASE)) {
				/* run withtout parent */
				mm_remove_all_depend(dmp_release);
			}
			goto lm_dm_error;
		}

		if (mm_dmp_add_cmd(mm_wka, cmd, mount_info->cmi_dm,
		    MM_DMP_LOAD) == NULL) {
			mms_trace(MMS_ERR,
			    "error adding dmp load");
			mm_system_error(cmd,
			    "error adding dmp load");
			goto reset_states;
		}
		cmd->cmd_state = 6;
		return (MM_DISPATCH_DEPEND);
	} else if (cmd->cmd_state == 6) {
		/* load command has finished, add an attach */
		/* Update Drive Table */
		if (cmd->cmd_flags & MM_CMD_DEPEND_ERROR) {
			mms_trace(MMS_DEVP, "mmp_mount-> DMP load error");
			/* Reset drive and cartridge */
			/* return error to client */
			mount_info->cmi_reset_states = 1;
			mount_info->cmi_need_clear = 1;
			/* DM is reserved, release the DM */
			if (dmp_release = mm_dmp_add_cmd(mm_wka,
			    NULL, mount_info->cmi_dm,
			    MM_DMP_RELEASE)) {
				/* run withtout parent */
				mm_remove_all_depend(dmp_release);
			}
			response_message =
			    mm_ret_response_msg(cmd);
			mm_response_error(cmd,
			    ECLASS_SUBOP,
			    "EDMPLOAD",
			    MM_5053_MSG,
			    "cartridge",
			    mount_info->cmi_cartridge,
			    "drive",
			    mount_info->cmi_drive,
			    "msg_rsp",
			    response_message,
			    NULL);
			free(response_message);
			cmd->cmd_remove = 1;
			mm_send_text(mm_wka->mm_wka_conn,
			    cmd->cmd_buf);
			rc = MM_CMD_ERROR;
			goto end;
		}

		if (mm_dmp_add_cmd(mm_wka, cmd, mount_info->cmi_dm,
		    MM_DMP_ATTACH) == NULL) {
			mms_trace(MMS_ERR,
			    "error adding dmp attach");
			mm_system_error(cmd,
			    "error adding dmp attach");
			goto reset_states;
		}
		cmd->cmd_state = 7;
		return (MM_DISPATCH_DEPEND);
	} else if (cmd->cmd_state == 7) {

		PGresult		*side;
		PGresult		*slot;
		PGresult		*mount_log;
		PGresult		*results;
		int			priv_no_vol = 0;
		char			*side_name = NULL;
		char			*slot_name = NULL;
		char			*slot_pcl = NULL;

		/* DM_identify tester state */
		if (cmd->cmd_flags & MM_CMD_DEPEND_ERROR) {
			mms_trace(MMS_DEVP, "mmp_mount-> DMP attach error");
			/* Reset drive and cartridge */
			/* return error to client */
			mount_info->cmi_reset_states = 1;
			mount_info->cmi_need_clear = 1;
			/* DM is reserved, release the DM */
			if (dmp_release = mm_dmp_add_cmd(mm_wka,
			    cmd, mount_info->cmi_dm,
			    MM_DMP_RELEASE)) {
				/* run withtout parent */
				mm_remove_all_depend(dmp_release);
			}
			/* write error message */
			response_message =
			    mm_ret_response_msg(cmd);
			mm_response_error(cmd,
			    ECLASS_SUBOP,
			    "EDMPATTACH",
			    MM_5054_MSG,
			    "cartridge",
			    mount_info->cmi_cartridge,
			    "drive",
			    mount_info->cmi_drive,
			    "msg_rsp",
			    response_message,
			    NULL);
			free(response_message);
			cmd->cmd_remove = 1;
			mm_send_text(mm_wka->mm_wka_conn,
			    cmd->cmd_buf);
			rc = MM_CMD_ERROR;
			goto end;
		}

		rc = mm_db_exec(HERE, db,
		    "select * from \"MOUNTPHYSICAL\" "\
		    "where \"CartridgeID\" = '%s';",
		    mount_info->cmi_cartridge);
		if (rc != MM_DB_DATA) {
			mms_trace(MMS_ERR, "Exec returned with no Data");
			mm_sql_db_err_rsp_new(cmd, db);
			goto reset_states;
		}
		mount_log = db->mm_db_results;
		rows = PQntuples(mount_log);
		mm_clear_db(&mount_log);
		/* attach command has finished, add an indentify */
		/* insert row into MOUNTLOGICAL */

		rc = mm_db_exec(HERE, db,
		    "select \"VolumeName\", "
		    "\"PartitionName\", \"SideName\" "
		    "from \"VOLUME\" where \"CartridgeID\" = '%s'"
		    "and \"ApplicationName\" = '%s';",
		    mount_info->cmi_cartridge,
		    conn->cci_client);

		if (rc != MM_DB_DATA) {
			mm_sql_db_err_rsp_new(cmd, db);
			goto reset_states;
		}
		results = db->mm_db_results;
		if ((PQntuples(results) == 0) &&
		    (cmd->wka_ptr->wka_privilege != MM_PRIV_STANDARD)) {
			/* Priv app doesn't have a volume */
			rc = mm_db_exec(HERE, db,
			    "select \"VolumeName\", "
			    "\"PartitionName\", \"SideName\", "
			    "\"ApplicationName\" "
			    "from \"VOLUME\" where \"CartridgeID\" = '%s';",
			    mount_info->cmi_cartridge);
			priv_no_vol = 1;
			mm_clear_db(&results);
			results = db->mm_db_results;
		}

		rc = mm_db_exec(HERE, db,
		    "select \"SideName\" from "	\
		    "\"SIDE\" where \"CartridgeID\" = '%s';",
		    mount_info->cmi_cartridge);
		if (rc != MM_DB_DATA) {
			mm_sql_db_err_rsp_new(cmd, db);
			mm_clear_db(&results);
			goto reset_states;
		}
		side = db->mm_db_results;


		if (PQntuples(side) == 0) {
			mms_trace(MMS_DEVP,
			    "missing SIDE obj for %s",
			    mount_info->cmi_cartridge);
			mm_system_error(cmd,
			    "cartridge missing SIDE obj");
			mm_clear_db(&results);
			mm_clear_db(&side);
			goto reset_states;
		}
		side_name = PQgetvalue(side, 0, 0);

		rc = mm_db_exec(HERE, db,
		    "select \"SlotName\", "\
		    "\"CartridgePCL\" from \"SLOT\" "\
		    "where \"CartridgeID\" = '%s';",
		    mount_info->cmi_cartridge);
		if (rc != MM_DB_DATA) {
			mm_sql_db_err_rsp_new(cmd, db);
			mm_clear_db(&results);
			mm_clear_db(&side);
			goto reset_states;
		}
		slot = db->mm_db_results;
		if (PQntuples(slot) == 0) {
			mms_trace(MMS_DEVP,
			    "missing SLOT obj for %s",
			    mount_info->cmi_cartridge);
			mm_system_error(cmd,
			    "cartridge missing SLOT obj");
			mm_clear_db(&results);
			mm_clear_db(&side);
			mm_clear_db(&slot);
			goto reset_states;
		}
		slot_name = PQgetvalue(slot, 0, 0);
		slot_pcl = PQgetvalue(slot, 0, 1);

		if (rows == 0) {
			if (priv_no_vol) {
				rc = mm_db_exec(HERE, db,
				    "insert into \"MOUNTLOGICAL\" "\
				    "(\"ApplicationName\", \"VolumeName\", "\
				    "\"PartitionName\", \"SideName\", "\
				    "\"CartridgeID\", \"DriveName\", "\
				    "\"DMName\", \"DMCapabilityName\", "\
				    "\"MountLogicalHandle\", "\
				    "\"MountLogicalTimeWhenMounted\") "\
				    "values ('%s', '%s', '%s', '%s', "\
				    "'%s', '%s', '%s', '%s', '%s', now());",
				    PQgetvalue(results, 0, 3),
				    PQgetvalue(results, 0, 0),
				    PQgetvalue(results, 0, 1),
				    PQgetvalue(results, 0, 2),
				    mount_info->cmi_cartridge,
				    mount_info->cmi_drive,
				    mount_info->cmi_dm,
				    mount_info->cmi_capability,
				    mount_info->cmi_handle);
			} else {
				rc = mm_db_exec(HERE, db,
				    "insert into \"MOUNTLOGICAL\" "
				    "(\"ApplicationName\", \"VolumeName\", "
				    "\"PartitionName\", \"SideName\", "
				    "\"CartridgeID\", \"DriveName\", "
				    "\"DMName\", \"DMCapabilityName\", "
				    "\"MountLogicalHandle\", "
				    "\"MountLogicalTimeWhenMounted\") "
				    "values ('%s', '%s', '%s', '%s', "
				    "'%s', '%s', '%s', '%s', '%s', now());",
				    conn->cci_client,
				    PQgetvalue(results, 0, 0),
				    PQgetvalue(results, 0, 1),
				    PQgetvalue(results, 0, 2),
				    mount_info->cmi_cartridge,
				    mount_info->cmi_drive,
				    mount_info->cmi_dm,
				    mount_info->cmi_capability,
				    mount_info->cmi_handle);
			}
			if (rc != MM_DB_OK) {
				mms_trace(MMS_ERR,
				    "mm_mount_cmd_func: "
				    "error inserting MOUNTLOGICAL");
			}

			if (mm_db_exec(HERE, db,
			    "insert into \"MOUNTPHYSICAL\" "
			    "(\"ApplicationName\",\"DriveName\", "
			    "\"LibraryName\", "
			    "\"CartridgeID\", \"CartridgePCL\", "
			    "\"SideName\", "
			    "\"SlotName\", "
			    "\"MountPhysicalTimeWhenMounted\", "
			    "\"SessionID\") "
			    "values('%s', '%s', '%s', '%s', "
			    "'%s', '%s', '%s', now(), '%s');",
			    conn->cci_client,
			    mount_info->cmi_drive,
			    mount_info->cmi_library,
			    mount_info->cmi_cartridge,
			    slot_pcl,
			    side_name,
			    slot_name,
			    mm_wka->session_uuid) != MM_DB_OK) {
				mms_trace(MMS_ERR,
				    "mm_mount_cmd_func: "
				    "error inserting MOUNTPHYSICAL");
			}
		} else {
			if (mm_db_exec(HERE, db,
			    "delete from \"MOUNTLOGICAL\" "\
			    "where \"CartridgeID\" = '%s';",
			    mount_info->cmi_cartridge) != MM_DB_OK) {
				mms_trace(MMS_ERR,
				    "mm_mount_cmd_func: "
				    "error deleting MOUNTLOGICAL");
			}
			rc = mm_db_exec(HERE, db,
			    "insert into \"MOUNTLOGICAL\" "\
			    "(\"ApplicationName\", \"VolumeName\", "\
			    "\"PartitionName\", \"SideName\", "\
			    "\"CartridgeID\", \"DriveName\", "\
			    "\"DMName\", \"DMCapabilityName\", "\
			    "\"MountLogicalHandle\", "\
			    "\"MountLogicalTimeWhenMounted\") "\
			    "values ('%s', '%s', '%s', '%s', "\
			    "'%s', '%s', '%s', '%s', '%s', now());",
			    conn->cci_client,
			    PQgetvalue(results, 0, 0),
			    PQgetvalue(results, 0, 1),
			    PQgetvalue(results, 0, 2),
			    mount_info->cmi_cartridge,
			    mount_info->cmi_drive,
			    mount_info->cmi_dm,
			    mount_info->cmi_capability,
			    mount_info->cmi_handle);
			if (rc != MM_DB_OK) {
				mms_trace(MMS_ERR,
				    "mm_mount_cmd_func: "
				    "error inserting MOUNTLOGICAL");
			}

		}
		mm_clear_db(&results);
		mm_clear_db(&side);
		mm_clear_db(&slot);
		if (mm_dmp_add_cmd(mm_wka, cmd, mount_info->cmi_dm,
		    MM_DMP_IDENTIFY) == NULL) {
			mms_trace(MMS_ERR,
			    "error adding dmp identify");
			mm_system_error(cmd,
			    "error adding dmp identify");
			goto reset_states;
		}
		cmd->cmd_state = 8;
		return (MM_DISPATCH_DEPEND);
	} else if (cmd->cmd_state == 8) {
		if (cmd->cmd_flags & MM_CMD_DEPEND_ERROR) {
			mms_trace(MMS_DEVP, "mmp_mount-> DMP identify error");
			/* Reset drive and cartridge */
			/* return error to client */
			mount_info->cmi_reset_states = 1;
			mount_info->cmi_need_clear = 1;
			/* DM is reserved, release the DM */
			if (dmp_release = mm_dmp_add_cmd(mm_wka,
			    cmd, mount_info->cmi_dm,
			    MM_DMP_RELEASE)) {
				/* run withtout parent */
				mm_remove_all_depend(dmp_release);
			}
			goto lm_dm_error;
		}
		/* The command is finished so generate a report */

		/* Remove the TASK objs */
		if (mm_db_exec(HERE, db, "delete from \"TASKCARTRIDGE\""
		    "where \"TaskID\" = '%s';",
		    cmd->cmd_uuid) != MM_DB_OK) {
			mms_trace(MMS_ERR,
			    "mm_mount_cmd_func: "
			    "db error deleting TASKCARTRIDGE");
		}
		if (mm_db_exec(HERE, db, "delete from \"TASKDRIVE\" "
		    "where \"TaskID\" = '%s';", cmd->cmd_uuid) != MM_DB_OK) {
			mms_trace(MMS_ERR,
			    "mm_mount_cmd_func: "
			    "db error deleting TASKDRIVE");
		}
		if (mm_db_exec(HERE, db, "delete from \"TASKLIBRARY\" "
		    "where \"TaskID\" = '%s';", cmd->cmd_uuid) != MM_DB_OK) {
			mms_trace(MMS_ERR,
			    "mm_mount_cmd_func: "
			    "db error deleting TASKLIBRARY");
		}
		if (mm_db_exec(HERE, db, "delete from \"TASK\" "
		    "where \"TaskID\" = '%s';", cmd->cmd_uuid) != MM_DB_OK) {
			mms_trace(MMS_ERR,
			    "mm_mount_cmd_func: "
			    "db error deleting TASK");
		}
		/*
		 * Report clause.
		 */
		cmd->cmd_remove = 1;
		mm_path_match_report(cmd, db);
		mm_send_response(mm_wka->mm_wka_conn, cmd);
		mms_trace(MMS_INFO, "Tape Successfully Mounted");
		rc = MM_CMD_DONE;
		goto end;

	}

	cmd->cmd_remove = 1;
	rc = MM_CMD_ERROR;
	goto end;

reset_states:
	mount_info->cmi_reset_states = 1;
	cmd->cmd_remove = 1;
	mm_send_text(mm_wka->mm_wka_conn, cmd->cmd_buf);
	return (MM_CMD_ERROR);
no_mem:
	MM_ABORT_NO_MEM();
	rc = MM_CMD_ERROR;
	goto end;

not_found:
	mm_response_error(cmd,
	    ECLASS_LANGUAGE,
	    ENOTFOUND,
	    MM_5062_MSG,
	    NULL);
	cmd->cmd_remove = 1;
	mm_send_text(mm_wka->mm_wka_conn, cmd->cmd_buf);
	rc = MM_CMD_ERROR;
	goto end;
lm_dm_error:
	response_message =
	    mm_ret_response_msg(cmd);
	mm_response_error(cmd,
	    ECLASS_SUBOP,
	    ELMDMCOMMUNICATION,
	    MM_5055_MSG,
	    "msg_rsp", response_message,
	    NULL);
	free(response_message);
	cmd->cmd_remove = 1;
	mm_send_text(mm_wka->mm_wka_conn, cmd->cmd_buf);
	/* Clear the Drive */
	if (mount_info->cmi_drive != NULL) {
		mount_info->cmi_need_clear = 1;

	}
	rc = MM_CMD_ERROR;
	goto end;

db_error:
	mm_sql_db_err_rsp_new(cmd, db);
	cmd->cmd_remove = 1;
	mm_send_text(mm_wka->mm_wka_conn,
	    cmd->cmd_buf);
	rc = MM_CMD_ERROR;
	goto end;

end:

	return (rc);

}


int
mm_delay_unmount_cmd_func(mm_wka_t *mm_wka, mm_command_t *cmd)
{

	time_t			tm;
	cmd_mount_info_t	*mount_info = &cmd->cmd_mount_info;
	mm_db_t			*db = &mm_wka->mm_data->mm_db;
	char			*response_message = NULL;

	mms_trace(MMS_DEVP, "mm_delay_unmount_cmd_func %s",
	    cmd->cmd_mount_info.cmi_drive);

	if (cmd->cmd_state == 0) {
		(void) time(&tm);

		if (tm < mount_info->unload_tm) {
			mms_trace(MMS_DEVP,
			    "wait longer for this unload");
			return (MM_DISPATCH_DEPEND);
		}

		if (mount_info->cui_skip_unload) {
			mms_trace(MMS_DEVP,
			    "procced with unload, "
			    "but skip the DM unload command");
			return (MM_CMD_DONE);
		}
		cmd->cmd_state = 1;
		mms_trace(MMS_DEVP,
		    "proceed with DM unload command");

	}

	if (cmd->cmd_state == 1) {
		if (mm_dmp_add_cmd(mm_wka, cmd, mount_info->cmi_dm,
		    MM_DMP_UNLOAD) == NULL) {
			mms_trace(MMS_ERR,
			    "mm_delay_unmount_cmd_func: "
			    "error adding dmp unload");
			return (MM_CMD_ERROR);
		}
		cmd->cmd_state = 2;
		return (MM_DISPATCH_DEPEND);
	}

	if (cmd->cmd_state == 2) {
		mm_command_t		*lmp_umnt_cmd;
		mm_wka_t		*lm_wka;
		uuid_text_t		 new_task;
		char			*cart_pcl;
		char			*side_name;
		/*
		 * Unload has returned
		 * check error, update states
		 */
		if (cmd->cmd_flags & MM_CMD_DEPEND_ERROR) {
			mms_trace(MMS_DEVP, "delay unmount-> DMP unload error");
			response_message = mm_ret_response_msg(cmd);
			mm_response_error(cmd,
			    ECLASS_SUBOP,
			    ELMDMCOMMUNICATION,
			    MM_5055_MSG,
			    "msg_rsp", response_message,
			    NULL);
			free(response_message);
			response_message = NULL;

		}

		/*
		 * Cartridge pcl and side name
		 */
		if ((cart_pcl = mm_get_cart_pcl(cmd,
		    cmd->cmd_mount_info.cmi_cartridge, db)) == NULL) {
			cmd->cmd_remove = 1;
			mms_trace(MMS_ERR,
			    "mm_get_cart_pcl error");
			return (MM_CMD_ERROR);
		}

		mm_set_mount_info_pcl(cart_pcl,
		    mount_info);

		/* TODO side name needs to be generated in candidate query */
		if ((side_name = cmd->cmd_mount_info.cmi_side_name) == NULL) {
			side_name = "side 1";
		}

		/*
		 * LMP unmount command
		 */
		lm_wka = mm_library_lm_wka(cmd->wka_ptr->mm_data,
		    cmd->cmd_mount_info.cmi_library, NULL);
		if ((lmp_umnt_cmd = mm_alloc_cmd(lm_wka)) == NULL) {
			mms_trace(MMS_ERR,
			    "Unable to malloc mm_command_t: %s",
			    strerror(errno));
			return (MM_CMD_ERROR);
		}
		lmp_umnt_cmd->cmd_func = mm_lmp_unmount_cmd_func;
		mm_get_uuid(new_task);
		lmp_umnt_cmd->cmd_textcmd = mms_strnew(LMP_UNMOUNT, new_task,
		    cart_pcl, cart_pcl, side_name,
		    cmd->cmd_mount_info.cmi_drive,
		    cart_pcl, cart_pcl, side_name);
		mm_set_mount_info_drive(cmd->cmd_mount_info.cmi_drive,
		    &lmp_umnt_cmd->cmd_mount_info);
		lmp_umnt_cmd->cmd_root =
		    mm_text_to_par_node(lmp_umnt_cmd->cmd_textcmd,
		    mms_lmpm_parse);
		lmp_umnt_cmd->cmd_task = mm_get_task(lmp_umnt_cmd->cmd_root);
		mm_add_depend(lmp_umnt_cmd, cmd);
		lmp_umnt_cmd->cmd_name = strdup("lmp unmount");


		cmd->cmd_state = 3;

		pthread_mutex_lock(&mm_wka->mm_data->mm_queue_mutex);
		mms_list_insert_tail(&mm_wka->mm_data->mm_cmd_queue,
		    lmp_umnt_cmd);
		pthread_mutex_unlock(&mm_wka->mm_data->mm_queue_mutex);

		free(cart_pcl);

		return (MM_DISPATCH_DEPEND);

	}
	if (cmd->cmd_state == 3) {
		if (cmd->cmd_flags & MM_CMD_DEPEND_ERROR) {
			mms_trace(MMS_ERR, "LMP unmount error, "
			    "scan both drive and slot");
			/* Clear depend error flags */
			MM_UNSET_FLAG(cmd->cmd_flags,
			    MM_CMD_DEPEND_ERROR);

			/* Add LMP scan command for this drive */
			if (mm_add_lmp_scan(mm_wka->mm_data, cmd,
			    mount_info->cmi_drive,
			    NULL, mount_info->cmi_library)) {
				mms_trace(MMS_ERR,
				    "Error adding LMP scan");
				return (MM_CMD_ERROR);
			} else {
				mms_trace(MMS_DEBUG,
				    "Added LMP scan");
			}
			cmd->cmd_state = 4;
			return (MM_DISPATCH_DEPEND);
		}


		mms_trace(MMS_INFO, "Tape Unmounted Successfully");
		/*
		 * Don't reset the soft state
		 * "\"DriveStateSoft\" = 'ready',"
		 */

		if (mm_db_exec(HERE, db, "update \"DRIVE\" set "
		    "\"DMName\" = '',"
		    "\"DriveStateHard\" = 'unloaded' where "
		    "\"DriveName\" = '%s';",
		    cmd->cmd_mount_info.cmi_drive) != MM_DB_OK) {
			mms_trace(MMS_ERR,
			    "mm_delay_unmount_cmd_func: "
			    "db error updating DriveStateHard");
		}

		/* Don't update the cartridge soft state */
		/* The unload may be part of a mount sequence */

		if (mm_has_depend(cmd)) {
			mm_command_t *cur_depend = NULL;
			mms_list_foreach(&cmd->cmd_depend_list, cur_depend) {
				if (cur_depend->cmd_func ==
				    mm_delay_unmount_cmd_func) {
					mms_trace(MMS_DEVP,
					    "this delay unmount has "
					    "delay unmount as parent,"
					    " set parent ready for dispatch");
					mm_set_unload_dispatch(cur_depend,
					    NULL);
				}
			}
			return (MM_DEPEND_DONE);
		}

		return (MM_CMD_DONE);
	}
	if (cmd->cmd_state == 4) {
		/* This is state after lmp scan of drive */
		/* send a scan of the cartridge now */
		if (cmd->cmd_flags & MM_CMD_DEPEND_ERROR) {
			mms_trace(MMS_ERR, "error in LMP drive scan, try"
			    "slot scan anyways");
			/* Clear depend error flags */
			MM_UNSET_FLAG(cmd->cmd_flags,
			    MM_CMD_DEPEND_ERROR);
		}
		mms_trace(MMS_DEVP, "drive scan done, scan slot");

		/* Add LMP scan command for this drive */
		if (mm_add_lmp_scan(mm_wka->mm_data, cmd,
		    NULL,
		    mount_info->cmi_pcl,
		    mount_info->cmi_library)) {
			mms_trace(MMS_ERR,
			    "Error adding LMP scan");
			return (MM_CMD_ERROR);
		} else {
			mms_trace(MMS_DEBUG,
			    "Added LMP scan");
		}
		cmd->cmd_state = 5;
		return (MM_DISPATCH_DEPEND);

	}
	if (cmd->cmd_state == 5) {
		/* cartridge scan returned , return cmd done */
		if (cmd->cmd_flags & MM_CMD_DEPEND_ERROR) {
			mms_trace(MMS_ERR, "error in LMP slot scan");
		}
		mms_trace(MMS_DEVP, "slot scan done");

		/* Don't update the cartridge soft state */
		/* The unload may be part of a mount sequence */

		if (mm_has_depend(cmd)) {
			mm_command_t *cur_depend = NULL;
			mms_list_foreach(&cmd->cmd_depend_list, cur_depend) {
				if (cur_depend->cmd_func ==
				    mm_delay_unmount_cmd_func) {
					mms_trace(MMS_DEVP,
					    "this delay unmount has "
					    "delay unmount as parent,"
					    " set parent ready for dispatch");
					mm_set_unload_dispatch(cur_depend,
					    NULL);
				}
			}
			return (MM_DEPEND_DONE);
		}

		return (MM_CMD_DONE);
	}

	mms_trace(MMS_ERR,
	    "mm_delay_unmount_cmd_func: unknown command state");
	return (MM_CMD_ERROR);

}


int
mm_schedule_unload(mm_wka_t *mm_wka, mm_command_t *cmd) {

	cmd_mount_info_t	*mount_info = &cmd->cmd_mount_info;
	mm_data_t		*mm_data = mm_wka->mm_data;
	mm_db_t			*db = &mm_wka->mm_data->mm_db;

	mm_command_t		*unmount_cmd;
	mm_wka_t		*lm_wka;
	uuid_text_t		uuid;

	/* Time releated */
	char		cur_date[100];
	char		unload_date[100];
	time_t		tm;
	struct tm	cur_time;
	struct tm	unload_time;

	/* allocate the unmount command */
	lm_wka = NULL;
	lm_wka = mm_library_lm_wka(cmd->wka_ptr->mm_data,
	    cmd->cmd_mount_info.cmi_library, NULL);
	if ((unmount_cmd = mm_alloc_cmd(lm_wka)) == NULL) {
		mms_trace(MMS_ERR,
		    "Unable to malloc mm_command_t: %s",
		    strerror(errno));
		return (1);
	}
	mm_get_uuid(uuid);
	unmount_cmd->cmd_root = NULL;
	unmount_cmd->cmd_task = NULL;
	unmount_cmd->cmd_task = strdup(uuid);
	unmount_cmd->cmd_func = mm_delay_unmount_cmd_func;
	unmount_cmd->cmd_name = strdup("delay unmount");

	/* Copy over the mount info to the new command */
	if (mount_info->cmi_cartridge != NULL)
		unmount_cmd->cmd_mount_info.cmi_cartridge =
		    strdup(mount_info->cmi_cartridge);
	if (mount_info->cmi_drive != NULL)
		unmount_cmd->cmd_mount_info.cmi_drive =
		    strdup(mount_info->cmi_drive);
	if (mount_info->cmi_side_name != NULL)
		unmount_cmd->cmd_mount_info.cmi_side_name =
		    strdup(mount_info->cmi_side_name);
	if (mount_info->cmi_library != NULL)
		unmount_cmd->cmd_mount_info.cmi_library =
		    strdup(mount_info->cmi_library);
	if (mount_info->cmi_dm != NULL)
		unmount_cmd->cmd_mount_info.cmi_dm =
		    strdup(mount_info->cmi_dm);

	unmount_cmd->cmd_mount_info.cui_skip_unload =
	    mount_info->cui_skip_unload;

	/* Set up timer */

	if (mm_db_exec(HERE, db,
	    "select \"DriveGroupUnloadTime\" from "
	    "\"DRIVEGROUP\",\"DRIVE\" where "
	    "\"DRIVE\".\"DriveGroupName\" = "
	    "\"DRIVEGROUP\".\"DriveGroupName\" and "
	    "\"DRIVE\".\"DriveName\" = '%s';",
	    mount_info->cmi_drive) != MM_DB_DATA) {
		mms_trace(MMS_ERR, "Exec returned with no Data");
		return (1);
	}
	if (PQntuples(db->mm_db_results) != 1) {
		mms_trace(MMS_ERR, "Exec rows != 1");
		mm_clear_db(&db->mm_db_results);
		return (1);
	}

	/* set the time to unload */
	/* Get the delay time, get the current time */
	(void) time(&tm);
	mms_trace(MMS_DEVP, "Current tm is %d", tm);
	(void) localtime_r(&tm, &cur_time);
	(void) strftime(cur_date, 100, "%Y/%m/%d %H:%M:%S", &cur_time);

	/* unload time is in min, so mult by 60 for sec */
	tm = tm + 60*atoi(PQgetvalue(db->mm_db_results, 0, 0));
	unmount_cmd->cmd_mount_info.unload_tm = tm;

	mms_trace(MMS_DEVP, "Unload tm is %d", tm);
	(void) localtime_r(&tm, &unload_time);
	(void) strftime(unload_date, 100, "%Y/%m/%d %H:%M:%S", &unload_time);
	mms_trace(MMS_DEVP,
	    "Current time is %s, delay time is %s mins, unload at %s",
	    cur_date, PQgetvalue(db->mm_db_results, 0, 0), unload_date);


	pthread_mutex_lock(&mm_data->
	    mm_queue_mutex);
	mms_list_insert_tail(&mm_data->mm_cmd_queue, unmount_cmd);
	pthread_mutex_unlock(&mm_data->
	    mm_queue_mutex);

	mm_clear_db(&db->mm_db_results);
	return (0);


}

int
mm_parse_unmount_cmd(mm_wka_t *mm_wka, mm_command_t *cmd) {


	cmd_mount_info_t	*mount_info = &cmd->cmd_mount_info;


	mms_par_node_t		*arg;
	mms_par_node_t		*value;

	mms_par_node_t		*work = NULL;


	mms_trace(MMS_DEVP, "mm_parse_unmount_cmd");
	mount_info->cmi_operation = MM_UNMOUNT;

	/* Get the type */
	mms_trace(MMS_DEVP, "type");
	MMS_PN_LOOKUP(arg, cmd->cmd_root, "type",
	    MMS_PN_CLAUSE, NULL);
	MMS_PN_LOOKUP(value, arg, NULL, MMS_PN_KEYWORD, NULL);
	if (strcmp(value->pn_string, "SIDE") == 0) {
		mount_info->cmi_type = MM_SIDE;
	} else if (strcmp(value->pn_string, "PARTITION") == 0) {
		mount_info->cmi_type = MM_PARTITION;
	} else if (strcmp(value->pn_string, "VOLUME") == 0) {
		mount_info->cmi_type = MM_VOLUME;
	}
	mms_trace(MMS_DEVP, "type %s", value->pn_string);

	if (mms_pn_lookup(cmd->cmd_root, "physicalunmount",
	    MMS_PN_KEYWORD, NULL)) {
		mount_info->cui_physical = 1;
	}
	mms_trace(MMS_DEVP, "physicalunmount %d",
	    mount_info->cui_physical);

	/* signature optional */
	if (arg = mms_pn_lookup(cmd->cmd_root, "signature",
	    MMS_PN_CLAUSE, NULL)) {
		value = mms_pn_lookup(arg, NULL, MMS_PN_KEYWORD,
		    NULL);
		if (value &&
		    strcmp(value->pn_string, "CLEAN") == 0) {
			mount_info->cui_signature_clean = 1;
			mms_trace(MMS_DEVP, "signature clean");
		} else {
			work = NULL;
			MMS_PN_LOOKUP(value, arg, NULL,
			    MMS_PN_STRING, &work);
			mount_info->cui_signature_type =
			    strdup(value->pn_string);
			MMS_PN_LOOKUP(value, arg, NULL,
			    MMS_PN_STRING, &work);
			mount_info->cui_signature =
			    strdup(value->pn_string);
			mms_trace(MMS_DEVP, "signature %s %s",
			    mount_info->cui_signature_type,
			    mount_info->cui_signature);
		}
	} else {
		/* default signature */
		mount_info->cui_signature_clean = 1;
		mms_trace(MMS_DEVP, "signature defaults to clean");
	}

	return (MM_CMD_DONE);

not_found:
	mm_response_error(cmd,
	    ECLASS_LANGUAGE,
	    ENOTFOUND,
	    MM_5062_MSG,
	    NULL);
	cmd->cmd_remove = 1;
	mm_send_text(mm_wka->mm_wka_conn, cmd->cmd_buf);
	return (MM_CMD_ERROR);
no_mem:
	MM_ABORT_NO_MEM();
	return (MM_CMD_ERROR);

}


PGresult*
mm_unmount_cart_results(mm_wka_t *mm_wka,
    mm_command_t *cmd, mm_db_t *db) {

	cmd_mount_info_t	*mount_info = &cmd->cmd_mount_info;
	char			*tmp_buf = NULL;

	cci_t			*conn = &mm_wka->wka_conn;
	char			*app_name = conn->cci_client;
	char			*type = NULL;
	int			i;



	mm_clear_source(cmd);
	mm_clear_dest(cmd);
	mm_clear_const(cmd);

	switch (mount_info->cmi_type) {
	case MM_SIDE:
		type = mms_strapp(type, MM_SIDE_STRING);
		break;
	case MM_PARTITION:
		type = mms_strapp(type, MM_PARTITION_STRING);
		break;
	case MM_VOLUME:
		type = mms_strapp(type, MM_VOLUME_STRING);
		break;
	}

	/* Do drive/cart/lib selection using path matching */

	if (mm_get_dest(mm_wka, cmd)) {
		/* Command does not have a match/volname clause */
		mms_trace(MMS_DEVP, "No match/volname Clause???");
	} else {
		/* TEMP - Trace out our dest info */
		mms_trace(MMS_DEVP, "Dest count is %d", cmd->cmd_dest_num);
		mm_print_char_list(&cmd->cmd_dest_list);
	}

	if (mm_get_const(mm_wka, cmd)) {
		/* Command does not have a match/volname clause */
		mms_trace(MMS_DEVP, "No match/volname Clause???");
	} else {
		/* TEMP - Trace out our const info */
		mms_trace(MMS_DEVP, "Const count is %d", cmd->cmd_const_num);
		mm_print_char_list(&cmd->cmd_const_list);
	}

	if (cmd->wka_ptr->wka_privilege == MM_PRIV_STANDARD) {
		/* add CARTRIDGEGROUPAPPLICATION constraint */
		(void) mm_add_to_dest(cmd,
		    "CARTRIDGEGROUPAPPLICATION");
		if (tmp_buf)
			free(tmp_buf);
		tmp_buf = NULL;
		tmp_buf = mms_strapp(tmp_buf,
		    "\"CARTRIDGEGROUPAPPLICATION\"."
		    "\"ApplicationName\" = '%s'",
		    app_name);
		(void) mm_add_to_const(cmd, tmp_buf);
		if (tmp_buf)
			free(tmp_buf);
		tmp_buf = NULL;
	}
	/* Constrain to only cartridges mounted by this session */
	/* Maybe a forced unmount will not use this constraint */
	(void) mm_add_to_dest(cmd,
	    "SESSION");
	if (tmp_buf)
		free(tmp_buf);
	tmp_buf = NULL;
	tmp_buf = mms_strapp(tmp_buf,
	    "\"SESSION\"."
	    "\"ConnectionID\" = '%s'",
	    conn->cci_uuid);
	(void) mm_add_to_const(cmd, tmp_buf);
	if (tmp_buf)
		free(tmp_buf);
	tmp_buf = NULL;

	/* Add MOUNTPHYSICAL constraint */
	/* Maybe a forced unmount will not use this constraint */
	(void) mm_add_to_dest(cmd,
	    "MOUNTPHYSICAL");
	if (tmp_buf)
		free(tmp_buf);
	tmp_buf = NULL;
	tmp_buf = mms_strapp(tmp_buf,
	    "(\"MOUNTPHYSICAL\".\"CartridgeID\" "
	    "= \"%s\".\"CartridgeID\")", type);
	(void) mm_add_to_const(cmd, tmp_buf);
	if (tmp_buf)
		free(tmp_buf);
	tmp_buf = NULL;
	/* Make tmp_buf and set source */
	(void) mm_add_to_source(cmd, type);
	tmp_buf = mms_strapp(tmp_buf,
	    "select \"%s\"."
	    "\"CartridgeID\" from\n ", type);
	if (type)
		free(type);
	type = NULL;

	SQL_CHK_LEN(&cmd->cmd_buf, NULL,
	    &cmd->cmd_bufsize, strlen(tmp_buf) + 1);
	strcpy(cmd->cmd_buf, tmp_buf);

	if (tmp_buf)
		free(tmp_buf);
	tmp_buf = NULL;

	if (mm_sql_from_where(cmd, db)) {
		mms_trace(MMS_ERR,
		    "mm_unmount_cart_results: "
		    "db error creating helper functions");
		return (NULL);
	}


	if (mm_db_exec(HERE, db, cmd->cmd_buf) != MM_DB_DATA) {
		mm_sql_db_err_rsp_new(cmd, db);
		return (NULL);
	}
	if (PQntuples(db->mm_db_results) == 0) {
		/* no cartridge matches */
		mms_trace(MMS_INFO,
		    "match statment in mount "
		    "didn't match any cartridge/volumes");
		mm_response_error(cmd,
		    ECLASS_EXPLICIT, ENOMATCH,
		    MM_5052_MSG,
		    NULL);
		return (NULL);
	}
	tmp_buf = mms_strapp(tmp_buf,
	    "select distinct \"CartridgeID\","
	    "\"LibraryName\",\"CartridgeGroupPriority\","
	    "\"CartridgeNumberMounts\", "
	    "\"CartridgeTypeName\",\"CartridgePCL\", "
	    "\"CartridgeDriveOccupied\" "
	    "from ( "
	    "select \"CartridgeID\",\"LibraryName\", "
	    "\"CartridgeGroupPriority\","
	    "\"CartridgeNumberMounts\", "
	    "\"CartridgeTypeName\",\"CartridgePCL\", "
	    "\"CartridgeDriveOccupied\" "
	    "from \"CARTRIDGE\",\"CARTRIDGEGROUP\"");
	for (i = 0; i < PQntuples(db->mm_db_results); i++) {
		if (i == 0) {
			tmp_buf = mms_strapp(tmp_buf, "where (");
		} else {
			tmp_buf = mms_strapp(tmp_buf, "or ");
		}
		tmp_buf = mms_strapp(tmp_buf, " (\"CartridgeID\" = '%s')",
		    PQgetvalue(db->mm_db_results, i, 0));
	}
	tmp_buf = mms_strapp(tmp_buf,
	    ") and"
	    "(\"CARTRIDGEGROUP\".\"CartridgeGroupName\" "
	    "= \"CARTRIDGE\".\"CartridgeGroupName\")"
	    "order by \"CARTRIDGE\".\"CartridgeTimeMountedLast\""
	    ") as foo order by \"CartridgeGroupPriority\";");
	mm_clear_db(&db->mm_db_results);
	if (mm_db_exec(HERE, db, tmp_buf) != MM_DB_DATA) {
		if (tmp_buf)
			free(tmp_buf);
		tmp_buf = NULL;
		mm_sql_db_err_rsp_new(cmd, db);
		return (NULL);
	}
	if (tmp_buf)
		free(tmp_buf);
	tmp_buf = NULL;
	return (db->mm_db_results);
no_mem:
	MM_ABORT_NO_MEM();
	return (NULL);
}

int
mm_unmount_ready(mm_wka_t *mm_wka, mm_command_t *cmd, mm_db_t *db) {

	cmd_mount_info_t	*mount_info = &cmd->cmd_mount_info;

	PGresult		*cart_results;
	int			cart_rows;

	int			found_cart_drive = 0;
	int			found_ready_cart_drive = 0;

	cmi_cart_list_t		*cart = NULL;
	cmi_drive_list_t	*drive = NULL;

	int			rc;

	/* Do drive/cart/lib selection using path matching */
	if ((cart_results = mm_unmount_cart_results(mm_wka,
	    cmd, db)) == NULL) {
		/* No carts or error */
		return (MM_UNMOUNT_ERROR);
	}

	cart_rows = PQntuples(cart_results);
	mms_trace(MMS_DEVP, "Number of Cartridges is %d", cart_rows);
	if (cart_rows == 0) {
		/* No Cartridge Matches Error */
		mms_trace(MMS_INFO,
		    "match statment in mount "
		    "didn't match any cartridge/volumes");
		mm_response_error(cmd,
		    ECLASS_EXPLICIT, ENOMATCH,
		    MM_5052_MSG,
		    NULL);
		mm_clear_db(&cart_results);
		return (MM_UNMOUNT_ERROR);
	}

	/* Create the list objects for */
	/* every cartridge/drive candidate */
	if (mm_mount_init_candidates(cmd, cart_results,
	    db)) {
		mms_trace(MMS_ERR,
		    "error initializing candidate lists");
		/* err buf should be set by mm_mount_init */
		/* so return and remove */
		mm_clear_db(&cart_results);
		return (MM_UNMOUNT_ERROR);
	}
	mms_trace(MMS_DEVP, "candidate list created, check availability ");
	mm_clear_db(&cart_results);
	/* Check the availability of the candidates */
	if (mm_mount_check_candidates(mm_wka, cmd,
	    db)) {
		mms_trace(MMS_ERR,
		    "error checking candidate lists");
		mm_system_error(cmd,
		    "error checking candidate lists");
		return (MM_UNMOUNT_ERROR);
	}
	mms_trace(MMS_DEVP, "done checking list");


	/* Print mount information */
	mm_print_mount_summary(mm_wka, cmd);
	found_cart_drive = 0;
	found_ready_cart_drive = 0;

	mms_list_foreach(&mount_info->cmi_cart_list, cart) {
		if (cart->cmi_cart_not_ready)
			cart->cmi_remove_cart = 1;
		mms_list_foreach(&cart->cmi_drive_list, drive) {
			found_cart_drive = 1;
			if ((cart->cmi_cart_not_ready == 0) &&
			    (drive->cmi_drive_not_ready == 0)) {
				found_ready_cart_drive = 1;
			}
			if (drive->cmi_drive_not_ready)
				drive->cmi_remove_drive = 1;
		}
	}


	/* If there is a library or drive error */
	/* the error buff has already been set */
	if (found_cart_drive == 0) {
		mms_trace(MMS_INFO,
		    "No candidate "
		    "cartridge/library/drive "
		    "combination found");
		return (MM_UNMOUNT_ERROR);
	}
	if (found_ready_cart_drive == 0) {
		mms_trace(MMS_INFO,
		    "candidate "
		    "cartridge/library/drive "
		    "combination found, but is not ready");
		return (MM_UNMOUNT_NOT_READY);
	}
	/* There is a ready cart/drive */
	/* we may have set some non ready for remove */
	/* so call the clean func before contine */
	mm_mount_clean_candidates(cmd);
	cmd->cmd_state = 1;
	rc = mm_set_immediate_unmount(cmd, db);

	if (rc == MM_CMD_ERROR) {
		mms_trace(MMS_ERR,
		    "error setting up immediate mount");
		return (MM_UNMOUNT_ERROR);
	}
	mms_trace(MMS_DEVP,
	    "mount ready for dispatch");

	return (MM_UNMOUNT_READY);

}

int
mm_unmount_cmd_func(mm_wka_t *mm_wka, mm_command_t *cmd)
{
	mm_db_t			*db = &mm_wka->mm_data->mm_db;
	cmd_mount_info_t	*mount_info = &cmd->cmd_mount_info;
	int			rc;
	char			*response_message = NULL;

	mms_trace(MMS_DEVP, "mm unmount state %d", cmd->cmd_state);
	mm_print_unmount_state(cmd->cmd_state);

	/* UM_CANDIDATE_SELECTION == 0 */
	if (cmd->cmd_state == UM_CANDIDATE_SELECTION)	{

		mms_trace(MMS_INFO, "Processing Unmount Request...");
		/*
		 * Generate Candidate Cartridge and Drive lists
		 * First parse and save the mount info
		 * then use SQL queries to gereate the lists
		 */

		if (mm_parse_unmount_cmd(mm_wka, cmd) == MM_CMD_ERROR) {
			mms_trace(MMS_ERR,
			    "error parsing unmount command");
			/* Error buf should already be set */
			cmd->cmd_remove = 1;
			mm_send_text(mm_wka->mm_wka_conn, cmd->cmd_buf);
			return (MM_CMD_ERROR);
		}
		mms_trace(MMS_DEVP, "done parsing unmount");

		if (mm_set_tm_task(db, cmd) != MM_DB_OK) {
			goto db_error;
		}
		mms_trace(MMS_DEVP,
		    "unmount will be passed to task manager");
		return (MM_WORK_TODO);

	} else if (cmd->cmd_state == UM_DM_DETACH) {
		mms_trace(MMS_INFO, "Unmounting Tape...");
		/*
		 * Add Detach command
		 */
		if (mm_dmp_add_cmd(mm_wka, cmd,
		    mount_info->cmi_dm,
		    MM_DMP_DETACH) == NULL) {
			mms_trace(MMS_ERR,
			    "mm_unmount_cmd_func: "
			    "error adding dmp unload");
			mm_system_error(cmd,
			    "error adding dmp unload");
			cmd->cmd_remove = 1;
			mm_send_text(mm_wka->mm_wka_conn,
			    cmd->cmd_buf);
			return (MM_CMD_ERROR);
		}
		cmd->cmd_state = UM_DM_RELEASE;
		return (MM_DISPATCH_DEPEND);

	}
	if (cmd->cmd_state == UM_DM_RELEASE) {
		/*
		 * Detach has returned
		 * check error, update states
		 * Add release command
		 */
		if (cmd->cmd_flags & MM_CMD_DEPEND_ERROR) {
			mms_trace(MMS_DEVP, "mmp_unmount-> DMP detach error");

			if ((cmd->cmd_response != NULL) &&
			    mm_errorcode_eq(cmd->cmd_response,
			    "DM_E_NOEXISTHANDLE")) {

				/* DM doesn't know about the handle */
				/* Continue with unmount regardless */
				/* skip unload */
				mms_trace(MMS_DEVP,
				    "DM doesn't know the handle, "
				    "skip DMP unload, "
				    "send LMP unmount");
				mount_info->cui_skip_unload = 1;
				/* Clear depend error flags */
				MM_UNSET_FLAG(cmd->cmd_flags,
				    MM_CMD_DEPEND_ERROR);
			} else {
				mount_info->cmi_reset_states = 1;
				mount_info->cmi_need_clear = 1;
				response_message =
				    mm_ret_response_msg(cmd);
				mm_response_error(cmd,
				    ECLASS_SUBOP,
				    ELMDMCOMMUNICATION,
				    MM_5055_MSG,
				    "msg_rsp", response_message,
				    NULL);
				free(response_message);
				cmd->cmd_remove = 1;
				mm_send_text(mm_wka->mm_wka_conn, cmd->cmd_buf);
				rc = MM_CMD_ERROR;
				goto end;
			}
		}

		if (mm_db_exec(HERE, db, "delete from \"MOUNTLOGICAL\" " \
		    "where \"CartridgeID\" = '%s';",
		    mount_info->cmi_cartridge) != MM_DB_OK) {
			mms_trace(MMS_ERR,
			    "mm_unmount_cmd_func: "
			    "db error deleteing MOUNTLOGICAL");
		}
		if (mm_db_exec(HERE, db, "delete from \"STALEHANDLE\" "\
		    "where \"CartridgeID\" = '%s';",
		    mount_info->cmi_cartridge) != MM_DB_OK) {
			mms_trace(MMS_ERR,
			    "mm_unmount_cmd_func: "
			    "db error deleteing STALEHANDLE");
		}

		if (mm_dmp_add_cmd(mm_wka, cmd, mount_info->cmi_dm,
		    MM_DMP_RELEASE) == NULL) {
			mms_trace(MMS_ERR,
			    "mm_unmount_cmd_func: "
			    "error adding dmp release");
			mm_system_error(cmd,
			    "error adding dmp release");
			cmd->cmd_remove = 1;
			mm_send_text(mm_wka->mm_wka_conn,
			    cmd->cmd_buf);
			return (MM_CMD_ERROR);
		}
		cmd->cmd_state = UM_SCHEDULE_UNLOAD;
		return (MM_DISPATCH_DEPEND);
	}
	if (cmd->cmd_state == UM_SCHEDULE_UNLOAD) {
		/*
		 * release command has returned
		 * check for errors, update states
		 */
		if (cmd->cmd_flags & MM_CMD_DEPEND_ERROR) {
			mms_trace(MMS_DEVP, "mmp_unmount-> DMP release error");
			mount_info->cmi_reset_states = 1;
			mount_info->cmi_need_clear = 1;
			mm_response_error(cmd,
			    ECLASS_SUBOP,
			    ELMDMCOMMUNICATION,
			    MM_5055_MSG,
			    "msg_rsp", mm_ret_response_msg(cmd),
			    NULL);
			cmd->cmd_remove = 1;
			mm_send_text(mm_wka->mm_wka_conn, cmd->cmd_buf);
			rc = MM_CMD_ERROR;
			goto end;
		}

		if (mount_info->cui_physical) {
			/* This is a physical unmount */
			cmd->cmd_state = UM_LM_UNMOUNT;

			if (mm_dmp_add_cmd(mm_wka, cmd, mount_info->cmi_dm,
			    MM_DMP_UNLOAD) == NULL) {
				mms_trace(MMS_ERR,
				    "mm_unmount_cmd_func: "
				    "error adding dmp unload");
				mm_system_error(cmd,
				    "error adding dmp unload");
				cmd->cmd_remove = 1;
				mm_send_text(mm_wka->mm_wka_conn,
				    cmd->cmd_buf);
				return (MM_CMD_ERROR);
			}
			rc = MM_DISPATCH_DEPEND;
			goto end;

		}
		/* Delayed unmount */

		mms_trace(MMS_DEVP,
		    "DELAY UNLOAD NOW!!!!");

		/* update drive and cartridge states */
		if (mm_db_exec(HERE, db, "update \"DRIVE\" set "
		    "\"DriveStateSoft\" = 'ready',"
		    "\"DMName\" = ''"
		    " where "
		    "\"DriveName\" = '%s';",
		    cmd->cmd_mount_info.cmi_drive) != MM_DB_OK) {
			mms_trace(MMS_ERR,
			    "mm_unmount_cmd_func: "
			    "db error updating DriveStateSoft");
		}

		if (mm_db_exec(HERE, db,
		    "update \"CARTRIDGE\" set \"CartridgeStatus\" "
		    "= 'available' where "
		    "\"CartridgeID\" = '%s';",
		    cmd->cmd_mount_info.cmi_cartridge) != MM_DB_OK) {
			mms_trace(MMS_ERR,
			    "mm_unmount_cmd_func: "
			    "db error updating CartridgeStatus");
		}

		if (mm_db_exec(HERE, db, "delete from \"TASKCARTRIDGE\""
		    "where \"TaskID\" = '%s';", cmd->cmd_uuid) != MM_DB_OK) {
			mms_trace(MMS_ERR,
			    "mm_unmount_cmd_func: "
			    "db error deleting TASKCARTRIDGE");
		}
		if (mm_db_exec(HERE, db, "delete from \"TASKDRIVE\" "
		    "where \"TaskID\" = '%s';", cmd->cmd_uuid) != MM_DB_OK) {
			mms_trace(MMS_ERR,
			    "mm_unmount_cmd_func: "
			    "db error deleting TASKDRIVE");
		}
		if (mm_db_exec(HERE, db, "delete from \"TASKLIBRARY\" "
		    "where \"TaskID\" = '%s';", cmd->cmd_uuid) != MM_DB_OK) {
			mms_trace(MMS_ERR,
			    "mm_unmount_cmd_func: "
			    "db error deleting TASKLIBRARY");
		}
		if (mm_db_exec(HERE, db, "delete from \"TASK\" "
		    "where \"TaskID\" = '%s';", cmd->cmd_uuid) != MM_DB_OK) {
			mms_trace(MMS_ERR,
			    "mm_unmount_cmd_func: "
			    "db error deleting TASK");
		}
		if (mm_db_exec(HERE, db, "delete from \"MOUNTPHYSICAL\" "
		    "where \"CartridgeID\" = '%s';",
		    mount_info->cmi_cartridge) != MM_DB_OK) {
			mms_trace(MMS_ERR,
			    "mm_unmount_cmd_func: "
			    "db error deleting MOUNTPHYSICAL");
		}


		if (mm_schedule_unload(mm_wka, cmd)) {
			mms_trace(MMS_ERR,
			    "mm_unmount_cmd_func: "
			    "error scheduling unload");
		}
		/* Send success for the unmount */
		mm_path_match_report(cmd, db);
		cmd->cmd_remove = 1;
		mm_send_response(mm_wka->mm_wka_conn, cmd);
		rc = MM_DISPATCH_AGAIN;
		goto end;

	}

	if (cmd->cmd_state == UM_LM_UNMOUNT) {
		mm_command_t		*lmp_umnt_cmd;
		mm_wka_t		*lm_wka;
		uuid_text_t		 new_task;
		char			*cart_pcl;
		char			*side_name;

		/*
		 * Unload has returned
		 * check error, update states
		 * Add release command
		 */
		if (cmd->cmd_flags & MM_CMD_DEPEND_ERROR) {
			mount_info->cmi_reset_states = 1;
			mount_info->cmi_need_clear = 1;

			mms_trace(MMS_DEVP, "mmp_unmount-> DMP unload error");
			response_message =
			    mm_ret_response_msg(cmd);
			mm_response_error(cmd,
			    ECLASS_SUBOP,
			    ELMDMCOMMUNICATION,
			    MM_5055_MSG,
			    "msg_rsp", response_message,
			    NULL);
			free(response_message);
			cmd->cmd_remove = 1;

			mm_send_text(mm_wka->mm_wka_conn, cmd->cmd_buf);

			rc = MM_CMD_ERROR;
			goto end;
		}

		/*
		 * Cartridge pcl and side name
		 */
		if ((cart_pcl = mm_get_cart_pcl(cmd,
		    cmd->cmd_mount_info.cmi_cartridge, db)) == NULL) {
			cmd->cmd_remove = 1;
			mms_trace(MMS_ERR,
			    "mm_get_cart_pcl error");
			return (MM_CMD_ERROR);
		}


		/* TODO side name needs to be generated in candidate query */
		if ((side_name = cmd->cmd_mount_info.cmi_side_name) == NULL) {
			side_name = "side 1";
		}

		/*
		 * LMP unmount command
		 */
		lm_wka = mm_library_lm_wka(cmd->wka_ptr->mm_data,
		    cmd->cmd_mount_info.cmi_library, NULL);
		if ((lmp_umnt_cmd = mm_alloc_cmd(lm_wka)) == NULL) {
			mms_trace(MMS_ERR,
			    "Unable to malloc mm_command_t: %s",
			    strerror(errno));
			return (MM_CMD_ERROR);
		}
		lmp_umnt_cmd->cmd_func = mm_lmp_unmount_cmd_func;
		mm_get_uuid(new_task);
		lmp_umnt_cmd->cmd_textcmd = mms_strnew(LMP_UNMOUNT, new_task,
		    cart_pcl, cart_pcl, side_name,
		    cmd->cmd_mount_info.cmi_drive,
		    cart_pcl, cart_pcl, side_name);
		mm_set_mount_info_drive(cmd->cmd_mount_info.cmi_drive,
		    &lmp_umnt_cmd->cmd_mount_info);
		mm_set_mount_info_pcl(cart_pcl,
		    &lmp_umnt_cmd->cmd_mount_info);
		lmp_umnt_cmd->cmd_root =
		    mm_text_to_par_node(lmp_umnt_cmd->cmd_textcmd,
		    mms_lmpm_parse);
		lmp_umnt_cmd->cmd_task = mm_get_task(lmp_umnt_cmd->cmd_root);
		mm_add_depend(lmp_umnt_cmd, cmd);
		lmp_umnt_cmd->cmd_name = strdup("lmp unmount");

		cmd->cmd_state = UM_FINAL;

		pthread_mutex_lock(&mm_wka->mm_data->mm_queue_mutex);
		mms_list_insert_tail(&mm_wka->mm_data->
		    mm_cmd_queue, lmp_umnt_cmd);
		pthread_mutex_unlock(&mm_wka->mm_data->mm_queue_mutex);

		free(cart_pcl);

		return (MM_DISPATCH_DEPEND);

	} else if (cmd->cmd_state == UM_FINAL) {

		if (cmd->cmd_flags & MM_CMD_DEPEND_ERROR) {
			mms_trace(MMS_DEVP, "lm unmount failed");
			mount_info->cmi_reset_states = 1;
			mount_info->cmi_need_clear = 1;
			response_message =
			    mm_ret_response_msg(cmd);
			mm_response_error(cmd,
			    ECLASS_SUBOP,
			    ELMDMCOMMUNICATION,
			    MM_5055_MSG,
			    "msg_rsp", response_message,
			    NULL);
			free(response_message);
			cmd->cmd_remove = 1;
			mm_send_text(mm_wka->mm_wka_conn, cmd->cmd_buf);
			rc = MM_CMD_ERROR;
			goto end;
		}

		/*
		 * TEMPORARY update drive states remove TASK objs
		 */

		/* If cmd_depend is set this is part of a begin-end group */
		/* so do not reset the drive state */
		if (mm_has_depend(cmd) == 0) {
			if (mm_db_exec(HERE, db, "update \"DRIVE\" set "
			    "\"DriveStateSoft\" = 'ready',"
			    "\"DMName\" = '',"
			    "\"DriveStateHard\" = 'unloaded' where "
			    "\"DriveName\" = '%s';",
			    cmd->cmd_mount_info.cmi_drive) != MM_DB_OK) {
				mms_trace(MMS_ERR,
				    "mm_unmount_cmd_func: "
				    "db error updating DRIVE");
			}

		} else {
			if (mm_db_exec(HERE, db, "update \"DRIVE\" set "
			    "\"DMName\" = '',"
			    "\"DriveStateHard\" = 'unloaded' where "
			    "\"DriveName\" = '%s';",
			    cmd->cmd_mount_info.cmi_drive) != MM_DB_OK) {
				mms_trace(MMS_ERR,
				    "mm_unmount_cmd_func: "
				    "db error updating DRIVE");
			}
		}
		if (mm_db_exec(HERE, db,
		    "update \"CARTRIDGE\" set \"CartridgeStatus\" "
		    "= 'available' where "
		    "\"CartridgeID\" = '%s';",
		    cmd->cmd_mount_info.cmi_cartridge) != MM_DB_OK) {
			mms_trace(MMS_ERR,
			    "mm_unmount_cmd_func: "
			    "db error updating CartridgeStatus");
		}


		if (mm_db_exec(HERE, db, "delete from \"TASKCARTRIDGE\""
		    "where \"TaskID\" = '%s';", cmd->cmd_uuid) != MM_DB_OK) {
			mms_trace(MMS_ERR,
			    "mm_unmount_cmd_func: "
			    "db error deleting TASKCARTRIDGE");
		}
		if (mm_db_exec(HERE, db, "delete from \"TASKDRIVE\" "
		    "where \"TaskID\" = '%s';", cmd->cmd_uuid) != MM_DB_OK) {
			mms_trace(MMS_ERR,
			    "mm_unmount_cmd_func: "
			    "db error deleting TASKDRIVE");
		}
		if (mm_db_exec(HERE, db, "delete from \"TASKLIBRARY\" "
		    "where \"TaskID\" = '%s';", cmd->cmd_uuid) != MM_DB_OK) {
			mms_trace(MMS_ERR,
			    "mm_unmount_cmd_func: "
			    "db error deleting TASKLIBRARY");
		}
		if (mm_db_exec(HERE, db, "delete from \"TASK\" "
		    "where \"TaskID\" = '%s';", cmd->cmd_uuid) != MM_DB_OK) {
			mms_trace(MMS_ERR,
			    "mm_unmount_cmd_func: "
			    "db error deleting TASK");
		}
		if (mm_db_exec(HERE, db, "delete from \"MOUNTPHYSICAL\" "
		    "where \"CartridgeID\" = '%s';",
		    mount_info->cmi_cartridge) != MM_DB_OK) {
			mms_trace(MMS_ERR,
			    "mm_unmount_cmd_func: "
			    "db error deleting MOUNTPHYSICAL");
		}

		/*
		 * Report clause.
		 */

		mm_path_match_report(cmd, db);
		cmd->cmd_remove = 1;
		mm_send_response(mm_wka->mm_wka_conn, cmd);
		mms_trace(MMS_INFO, "Tape Unmounted Successfully");

		if (mm_has_depend(cmd)) {
			mm_command_t *cur_depend = NULL;
			mms_list_foreach(&cmd->cmd_depend_list, cur_depend) {
				if (cur_depend->cmd_func ==
				    mm_delay_unmount_cmd_func) {
					mms_trace(MMS_DEVP,
					    "this delay unmount has "
					    "delay unmount as parent,"
					    " set parent ready for dispatch");
					mm_set_unload_dispatch(cur_depend,
					    NULL);
				}
			}
			rc = MM_DEPEND_DONE;
			goto end;
		}
		rc = MM_CMD_DONE;
		goto end;
	}
	mms_trace(MMS_ERR, "Unknown state");
	cmd->cmd_remove = 1;
	rc = MM_CMD_ERROR;
	goto end;

no_mem:
	MM_ABORT_NO_MEM();
	rc = MM_CMD_ERROR;
	goto end;

not_found:
	mm_response_error(cmd,
	    ECLASS_LANGUAGE,
	    ENOTFOUND,
	    MM_5062_MSG,
	    NULL);
	cmd->cmd_remove = 1;
	mm_send_text(mm_wka->mm_wka_conn, cmd->cmd_buf);
	rc = MM_CMD_ERROR;
	goto end;
db_error:
	mm_sql_db_err_rsp_new(cmd, db);
	cmd->cmd_remove = 1;
	mm_send_text(mm_wka->mm_wka_conn,
	    cmd->cmd_buf);
	rc = MM_CMD_ERROR;
	goto end;

end:
	return (rc);

}



int
mm_begin_cmd_func(mm_wka_t *mm_wka, mm_command_t *cmd)
{
	mms_par_node_t		*arg;
	mms_par_node_t		*value;
	mm_db_t			*db = &mm_wka->mm_data->mm_db;

	mms_trace(MMS_DEVP, "sql trans begin cmd");
	if (cmd->cmd_state == 0) {
		mms_trace(MMS_DEVP, "when");
		arg = mms_pn_lookup(cmd->cmd_root, "when",
		    MMS_PN_CLAUSE, NULL);
		if (arg != NULL) {
			MMS_PN_LOOKUP(value,
			    arg, NULL, MMS_PN_KEYWORD, NULL);
			if (strcmp(value->pn_string, "blocking") == 0) {
				mm_wka->wka_begin_end.be_mode =
				    ACCESS_MODE_BLOCKING;
			} else {
				mm_wka->wka_begin_end.be_mode =
				    ACCESS_MODE_IMMEDIATE;
			}
		} else {
			/* when is optional and defaults to immediate */
			mm_wka->wka_begin_end.be_mode = ACCESS_MODE_IMMEDIATE;
		}
		mms_trace(MMS_DEVP, "ready for mount unmount command group");
		/* return MM_DISPATCH_DEPEND??? */
		cmd->cmd_state = 1;
		return (MM_DISPATCH_DEPEND);
	}
	if (cmd->cmd_state == 1) {
		/* when End has been accepted, send success for begin */
		/* Send success */
		mm_path_match_report(cmd, db);
		cmd->cmd_remove = 1;
		mm_send_response(mm_wka->mm_wka_conn, cmd);
		return (MM_DEPEND_DONE);
	}

	mms_trace(MMS_ERR,
	    "bad command state- begin command");
	mm_system_error(cmd,
	    "bad command state- begin command");
	mm_send_text(mm_wka->mm_wka_conn, cmd->cmd_buf);
	mm_wka->wka_begin_end.be_active = B_FALSE;
	cmd->cmd_remove = 1;
	return (MM_CMD_ERROR);

no_mem:
	MM_ABORT_NO_MEM();
	return (MM_CMD_ERROR);

not_found:
	mm_response_error(cmd,
	    ECLASS_LANGUAGE,
	    ENOTFOUND,
	    MM_5062_MSG,
	    NULL);
	cmd->cmd_remove = 1;
	mm_send_text(mm_wka->mm_wka_conn, cmd->cmd_buf);
	return (MM_CMD_ERROR);
}


void
mm_mv_beginend(mm_command_t *begin, mm_command_t *end) {
	/* begin end command list */
	mm_command_t *cur_cmd;
	mm_command_t *next_cmd;

	/* Move beginend commands from begin to end */
	for (cur_cmd = mms_list_head(&begin->cmd_beginend_list);
	    cur_cmd != NULL;
	    cur_cmd = next_cmd) {
		next_cmd =
		    mms_list_next(&begin->cmd_beginend_list,
		    cur_cmd);
		mms_list_remove(&begin->cmd_beginend_list,
		    cur_cmd);
		mms_list_insert_tail(&end->cmd_beginend_list,
		    cur_cmd);
	}
}

int
mm_be_parse_cmds(mm_command_t *cmd) {

	mm_command_t	*cur_cmd;
	int		cmd_count = 0;
	mm_wka_t	*mm_wka = cmd->wka_ptr;

	cmd_count = 0;
	mms_list_foreach(&cmd->cmd_beginend_list, cur_cmd) {
		cmd_count ++;
		mms_trace(MMS_DEVP,
		    "Begin-end cmd %d, %s",
		    cmd_count, cur_cmd->cmd_name);

		if (cur_cmd->cmd_func == mm_mount_cmd_func) {
			if (mm_parse_mount_cmd(cur_cmd->wka_ptr,
			    cur_cmd) == MM_CMD_ERROR) {
				mms_trace(MMS_ERR,
				    "error parsing unmount command");
				/* Error buf should already be set */
				return (-1);
			}
		} else {
			if (mm_parse_unmount_cmd(cur_cmd->wka_ptr,
			    cur_cmd) == MM_CMD_ERROR) {
				mms_trace(MMS_ERR,
				    "error parsing unmount command");
				/* Error buf should already be set */
				return (-1);
			}
		}
		if (mm_wka->wka_begin_end.be_mode == ACCESS_MODE_IMMEDIATE) {
			cur_cmd->cmd_mount_info.cmi_when = MM_IMMEDIATE;
		} else {
			cur_cmd->cmd_mount_info.cmi_when = MM_BLOCKING;
		}
	}
	return (cmd_count);
}

int
mm_end_cmd_func(mm_wka_t *mm_wka, mm_command_t *cmd)
{
	mm_command_t		*be_command = NULL;
	int			cmd_count;
	mm_db_t			*db = &mm_wka->mm_data->mm_db;

	mms_trace(MMS_DEVP, "mm_end_cmd_func");
	if (cmd->cmd_state == 0) {
		be_command = cmd->cmd_begin_cmd;
		if (be_command == NULL) {
			mms_trace(MMS_ERR,
			    "couldn't find begin for this end");
			mm_system_error(cmd,
			    "couldn't find begin for this end");
			cmd->cmd_remove = 1;
			mm_send_text(mm_wka->mm_wka_conn, cmd->cmd_buf);
			return (MM_CMD_ERROR);
		}

		/* Copy begin cmd list ptr */
		/* set begin for dispatch */
		/* as depend */
		mm_add_depend(be_command, cmd);
		mm_mv_beginend(be_command, cmd);
		MM_SET_FLAG(be_command->cmd_flags,
		    MM_CMD_DISPATCHABLE);
		cmd->cmd_state = 1;
		return (MM_DISPATCH_DEPEND);
	}
	if (cmd->cmd_state == 1) {
		/* Begin has returned success */

		/* abort command group */
		if (mms_pn_lookup(cmd->cmd_root, "abort",
		    MMS_PN_KEYWORD, NULL)) {
			/* Cancel all the commands */
			/* and return success for the abort */
			mms_trace(MMS_DEVP, "begin-end abort");
			mm_path_match_report(cmd, db);
			cmd->cmd_remove = 1;
			mm_send_text(mm_wka->mm_wka_conn, cmd->cmd_buf);
			tm_be_cancel_all(cmd);
			return (MM_CMD_DONE);
		}

		if ((cmd_count = mm_be_parse_cmds(cmd)) == -1) {
			/* Error parsing a command */
			mm_system_error(cmd,
			    "error parsing mount/unmount "
			    "inside begin-end group");
			cmd->cmd_remove = 1;
			mm_send_text(mm_wka->mm_wka_conn, cmd->cmd_buf);
			return (MM_CMD_ERROR);

		} else if (cmd_count == 0) {
			/* No commands in this command group */
			/* Send success ??? */
			mm_path_match_report(cmd, db);
			cmd->cmd_remove = 1;
			mm_send_response(mm_wka->mm_wka_conn, cmd);
			return (MM_CMD_DONE);
		}

		mms_trace(MMS_DEVP,
		    "done parsing %d commands for begin-end group",
		    cmd_count);
		if (mm_set_tm_task(db, cmd) != MM_DB_OK) {
			mm_sql_db_err_rsp_new(cmd, db);
			cmd->cmd_remove = 1;
			mm_send_text(mm_wka->mm_wka_conn, cmd->cmd_buf);
			return (MM_CMD_ERROR);
		}
		cmd->cmd_state = 2;
		mms_trace(MMS_DEVP,
		    "begin-end group will be passed to task manager");

		return (MM_WORK_TODO);
	}
	if (cmd->cmd_state == 2) {
		/* Task manager has dispatched this command */
		/* Send success for end */
		mms_trace(MMS_DEVP, "end command state 2");

		cmd->cmd_remove = 1;
		return (MM_CMD_DONE);
	}
	mms_trace(MMS_ERR,
	    "bad command state- end command");
	mm_system_error(cmd,
	    "bad command state- end command");
	mm_send_text(mm_wka->mm_wka_conn, cmd->cmd_buf);
	cmd->cmd_remove = 1;
	return (MM_CMD_ERROR);

no_mem:
	MM_ABORT_NO_MEM();
	return (MM_CMD_ERROR);

}