dm_target.c revision d1d2228c6cf3ec632d28262810ab7902932a5d33
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <limits.h>
#include <pthread.h>
#include <synch.h>
#include <ctype.h>
#include <signal.h>
#include <pwd.h>
#include <auth_attr.h>
#include <secdb.h>
#include <ucred.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dlfcn.h>
#include <link.h>
#include <strings.h>
#include <dirent.h>
#include <errno.h>
#include <dmd_impl.h>
#include <dm_impl.h>
#include <dm_drive.h>
#include <mms_sym.h>
#include <dm_msg.h>
#include <mms_trace.h>
#include <mms_dmd.h>
#include <dm_proto.h>
#include <mms_strapp.h>
/*
* Minor device number of the ST driver.
*
* Change device to bn device - turn BSD and norewind bits
*
* The minor device byte structure is (from mtio(7I)):
*
* 15-7 6 5 4 3 2 1 0
* ___________________________________________________________________
* Unit # BSD Reserved Density Density No rewind Unit #
* behavior Select Select on Close Bits 0-1
*
*/
{
return (minor);
}
dm_hdl_minor(void)
{
return (minor);
}
int
dm_get_target_base(void)
{
/*
* Serial number unknown. Have to use specified path
*/
return (dm_get_target_pathname());
} else {
/*
* for device matching serial number.
*/
return (dm_get_target_by_serial_num());
}
}
int
dm_get_target_pathname(void)
{
char *show_cmd;
char *task;
char *val;
"show task['%s'] reportmode[namevalue] "
"match[streq(DM.'DMName' '%s')] "
"unable to get DM.'DMTargetPath'"));
if (cmd) {
}
return (-1);
}
/*
* Save tape path
*/
"No TargetPath"));
return (-1);
}
if (dm_verify_target_dev(val) != 0) {
"invalid device pathname \"%s\"", val));
return (-1);
}
wka->dm_target_base));
return (0);
}
int
{
char **dirtab;
int i;
int rc = -1;
/*
* Search in the default dir
*/
/* Found it */
return (0);
}
/*
* Build a dir table from *.so
*/
dirtab = dm_bld_dir_tab();
return (-1);
}
/*
* Search each entry in dir table
*/
if (dm_probe_dir(dirtab[i]) == 0) {
/* Found it */
rc = 0;
break;
}
}
/*
* Can't find a device that matches the serial number
*/
}
return (rc);
}
int
dm_probe_dir(char *dirname)
{
int len;
int fd;
int rc = -1;
struct ent {
char *name;
};
int nument = 0;
int probe = 1;
int i;
int err;
int zero = 0;
"unable to open directory %s: %s",
return (-1);
}
/*
* Read the serial number of this device
*/
if (len < 2) {
/* Device name must be >= 2 chars */
continue;
}
/* If tape device, look at only norewind devices */
continue;
}
}
nument++;
}
while (probe) {
/*
* Continue to probe until all devices are probed.
*/
probe = 0;
for (i = 0; i < nument; i++) {
/*
* Set the ino in dmd. If EBUSY, then skip for now
*/
/* Already checked */
continue;
}
/*
* Tell DMD probing this device
*/
continue;
}
"unable to probe device: %s",
rc = -1;
goto done;
}
/*
* Check serial number of this device
*/
probe = 1;
do {
if (fd < 0) {
/*
* If can't open this device,
* then skip it
*/
"%s: %s",
break;
}
/* Read the serial number */
/* drv_*() uses drv->drv_fd */
(sernum)) != 0) {
"serial num error: %s: %s",
/* restoredrv->drv_fd */
break;
}
/* restoredrv->drv_fd */
/*
* Compare serial numbers
*/
/* Found device matching serial num */
/* Drop the "n" from pathname */
'\0';
"Target base is %s",
wka->dm_target_base));
rc = 0;
probe = 0; /* probe done */
}
} while (zero);
/*
* Unlock this dev
*/
if (probe == 0) {
break;
}
}
if (nument == i) {
DM_MSG_PREPEND(("dm_probe_dir: "
"cannot find a matching drive "
"with serial num %s in \"%s\": ",
}
}
done:
for (i = 0; i < nument; i++) {
}
}
return (rc);
}
char **
dm_bld_dir_tab(void)
{
char **dirtab;
char **newtab;
int taboff = 0;
int size = DRV_DIR_TAB_SIZE;
char *libpath;
char *libname;
int len;
void *dlhdl;
char *devdir;
int i;
"out of memory"));
return (NULL);
}
"unable to open %s", DM_DEV_LIB_DIR));
return (NULL);
}
/* Not lib*.so */
continue;
}
"unable to open %s", libpath));
continue;
}
if (devdir[0] == '\0') {
/* dev dir not specified */
continue;
}
/* Already probed DRV_TAPE_DIR */
continue;
}
/*
* Add to dirtab if not in it already
*/
/* dir name already in dirtab */
continue;
}
}
/* Not in table yet */
taboff++;
size += DRV_DIR_TAB_SIZE;
newtab = (char **)
"out of memory"));
return (NULL);
}
}
}
}
/*
* Done
*/
return (dirtab);
}
/*
* Verify target device name
*/
int
dm_verify_target_dev(char *devname)
{
int i;
if (devname[0] == '\0') {
return (-1);
}
/* If not a tape dev, ignore */
return (0);
}
return (-1);
}
/*
* strip device attribute from devname
*/
devname[i] = '\0';
return (0);
}
}
return (0);
}
int
dm_stat_targ_base(void)
{
int fd;
"target base device not available"));
return (-1);
}
"stat '%s' error: %s",
if (fd >= 0) {
}
return (-1);
}
return (0);
}
int
dm_reserve_target(void)
{
int rc = 0;
for (;;) {
rc = dm_reserve_target_prsv();
if (rc == 0) { /* drive reserved */
break;
} else if (rc > 0) {
/* error other than reservation conflict */
"unable to reserve drive: "
"I/O error"));
return (-1);
}
/*
* If already have MMS reservation, just preempt it.
* Otherwise see if we have to ask.
*/
if (!dm_have_mms_rsv()) { /* no mms rsv */
rc = dm_ask_preempt();
}
if (rc == DM_REP_ERROR) {
/* Ask got an error, assume "no" */
}
"drive reservation "
"denied by operator"));
return (-1);
} else if (rc == DM_REP_RETRY) {
sleep(1);
continue;
}
}
if (rc == DM_REP_YES) {
if (dm_preempt_rsv()) {
return (-1);
}
rc = 0;
break;
}
}
} else {
rc = dm_reserve_target_rsv();
}
return (rc);
}
int
dm_reserve_target_prsv(void)
{
int status = 0;
/*
* Register key
*/
if (DRV_CALL(drv_prsv_register, ())) {
"reservation key: \"%16.16llx\": %s",
if (status == STATUS_RESERVATION_CONFLICT) {
"unable to register key, "
"reservation conflict"));
return (-1);
} else {
/* other error */
return (EIO);
}
}
/*
* Do an exclusive persistent reservation
*/
if (DRV_CALL(drv_prsv_reserve, ()) != 0) {
if (status == STATUS_RESERVATION_CONFLICT) {
"unable to reserve drive: "
"reservation conflict"));
return (-1);
} else {
/* other error */
return (EIO);
}
}
/*
* Now, get rid of all the attentions
*/
;
}
DRVNAME));
return (0);
}
int
dm_reserve_target_rsv(void)
{
int rc = 0;
/*
* Since the target is opened (via ldi_open()) with O_NDELAY,
* until an I/O is done. A TUR will be done after binding
* the target. This causes the st driver to reserve the drive.
*/
/*
* Drive is reserved, find out if it is assigned to
* another DM
*/
if (dm_drv_assigned() != 0) {
/*
* No, not assigned. This means that the drive
* is being used by a non MMS client.
*/
/* Do not preempt */
return (-1);
}
rc = dm_ask_freserve();
}
if (rc == DM_REP_ERROR) {
/* Ask got an error, assume "no" */
}
if (rc == DM_REP_YES) {
return (-1);
}
return (-1);
} else if (rc == DM_REP_RETRY) {
continue;
}
} else {
/*
* If drive is assigned to another DM, then
* silently wait for it to be unassigned.
*/
"another DM. "
"Will keep trying reserve until "
}
}
/*
* Release the reservation made by the ST driver and tell it
* Then do my own reservations
*/
DRV_CALL(drv_release, ());
if (DRV_CALL(drv_reserve, ()) != 0) {
return (-1);
}
return (0);
}
int
dm_release_target(void)
{
DRV_CALL(drv_release, ());
return (0);
}
/*
* Using persistent reserve out
*/
DRV_CALL(drv_prsv_register, ());
DRV_CALL(drv_prsv_release, ());
return (0);
}
int
dm_force_release(void)
{
return (-1);
}
if (DRV_CALL(drv_release, ()) != 0) {
return (-1);
}
return (0);
}
int
dm_preempt_rsv(void)
{
char buf[24];
if (DRV_CALL(drv_prsv_register, ()) != 0 ||
/* Try force reserve and release */
if (dm_force_release() != 0) {
/* Can't force release */
return (-1);
}
if (DRV_CALL(drv_prsv_register, ()) != 0 ||
DRV_CALL(drv_prsv_reserve, ())) {
"persistent reservation " "error"));
return (-1);
}
return (0);
} else {
/* Other error */
return (-1);
}
}
if (num == 0) { /* no reservation */
if (DRV_CALL(drv_prsv_register, ()) != 0 ||
DRV_CALL(drv_prsv_reserve, ()) != 0) {
"persistent reservation " "error"));
return (-1);
}
} else {
/* Preempt the current reservation */
"persistent reservation preempt" "error"));
return (-1);
}
}
return (0);
}
int
dm_have_mms_rsv(void)
{
char buf[24];
if (DRV_CALL(drv_prsv_register, ()) != 0 ||
"unable to read reservation"));
/* Can't read reservation */
return (0);
}
if (num == 0) { /* no reservation */
return (0);
}
return (0);
}
/*
* Have MMS reservation
*/
return (1);
}
int
dm_rebind_target(void)
{
"Rebind base device error: %s",
return (-1);
}
return (0);
}
int
dm_open_dm_device(void)
{
int fd;
/*
* Open the drive manager device
*/
if (fd < 0) {
"open '%s' error: %s",
return (-1);
}
return (0);
}
int
dm_bind_target(void)
{
/*
* Get the major and minor of the DRM device
*/
/*
* Bind the drive manager to the target device.
* Since the target is opened (via ldi_open()) with O_NDELAY,
* until an I/O is done. A TUR will be done after binding
* the target. This causes the st driver to reserve the drive.
*/
if (dm_bind_target_base() != 0) {
return (-1);
}
return (0);
}
/*
* Bind manager drive to target
*/
int
dm_bind_target_base(void)
{
int err;
char pid[20];
/* drive is still opened. wait for close */
"Waiting for App to close target device, pid %s",
pid));
"waiting for close"));
} else {
return (-1);
}
}
wka->dm_drm_path));
return (0);
}
int
dm_bind_raw_dev(int oflag)
{
int err;
char *path;
char *den = "";
char *bsd = "";
char *rew = "";
den = "l";
den = "m";
den = "h";
den = "c";
}
/* MMS mode always use "b" */
bsd = "b";
}
/* MMS mode always use "n" */
rew = "n";
}
return (err);
}
return (err);
}
dm_clear_dev();
return (0);
}
void
dm_init_sense_buf(void)
{
struct scsi_extended_sense *es;
/* Can't read sense data */
"to %d", sizeof (struct scsi_extended_sense)));
return;
}
sizeof (struct scsi_arq_status) -
}
}
}
char *
{
/*
* Given the pid, return the user login name
*/
setpwent();
endpwent();
return (NULL);
}
endpwent();
}
int
dm_chk_dev_auth(char *user)
{
/*
* Check to see if the user is authorized to use MMS
*/
setauthattr();
endauthattr();
return (-1);
}
endauthattr();
return (0);
}