/*
 * devstat.c - Get information about a SAMFS device.
 *
 */

/*
 *    SAM-QFS_notice_begin
 *
 *      Solaris 2.x Sun Storage & Archiving Management File System
 *
 *		Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
 *
 *		U.S. Government Rights - Commercial software. Government users are
 *	subject to the Sun Microsystems, Inc. standard license agreement and applicable
 *	provisions of the FAR and its supplements.
 *
 *      	Use is subject to license terms. Sun, Sun Microsystems and the Sun logo
 *	are trademarks or registered trademarks of Sun Microsystems, Inc. in the U.S.
 *	and other countries.
 *
 *    SAM-QFS_notice_end
 */

/*
 *	LGPL NOTICE
 *
 *	This library is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU Lesser General Public
 *	License as published by the Free Software Foundation; either
 *	version 2.1 of the License, or (at your option) any later version.
 *
 *	This library is distributed in the hope that it will be useful,
 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *	Lesser General Public License for more details.
 *
 *	You should have received a copy of the GNU Lesser General Public
 *	License along with this library; if not, write to the Free Software
 *	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#pragma ident "$Revision$"

#include <sys/types.h>
#include <sys/shm.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

#include "aml/device.h"
#include "pub/devstat.h"
#include "aml/shm.h"

int
sam_devstat(
	    ushort_t eq,
	    struct sam_devstat * buf,
	    size_t bufsize)
{
	struct dev_ent *dev;
	dev_ptr_tbl_t  *dev_tbl;
	shm_alloc_t	master_shm;
	shm_ptr_tbl_t  *shm_ptr_tbl;
	struct sam_devstat db;

	if (bufsize < sizeof (db)) {
		errno = EINVAL;
		return (-1);
	}

	/*
	 * Access SAM-FS shared memory segment.
	 */
	if ((master_shm.shmid = shmget(SHM_MASTER_KEY, 0, 0)) < 0) {
#ifdef DEBUG
		fprintf(stderr, "Unable to find master shared memory segment.\n");
#endif				/* DEBUG */
		return (-1);
	}
	if ((master_shm.shared_memory =
		shmat(master_shm.shmid, NULL, 0)) == (void *)-1) {
#ifdef DEBUG
		fprintf(stderr, "Unable to attach master shared memory segment.\n");
#endif				/* DEBUG */
		return (-1);
	}
	shm_ptr_tbl = (shm_ptr_tbl_t *)master_shm.shared_memory;
	if (strcmp(shm_ptr_tbl->shm_block.segment_name, SAM_SEGMENT_NAME) != 0) {
#ifdef DEBUG
		fprintf(stderr, "Master shared memory segment name incorrect.\n");
#endif				/* DEBUG */
		shmdt((char *) master_shm.shared_memory);
		errno = ENOENT;
		return (-1);
	}
	dev_tbl = (dev_ptr_tbl_t *)
		SHM_REF_ADDR(shm_ptr_tbl->dev_table);
	if ((int) eq > dev_tbl->max_devices) {
		shmdt((char *) master_shm.shared_memory);
		errno = ENODEV;
		return (-1);
	}
	dev = (dev_ent_t *)SHM_REF_ADDR(dev_tbl->d_ent[eq]);
	if (dev == NULL) {
		shmdt((char *) master_shm.shared_memory);
		errno = ENODEV;
		return (-1);
	}
	if (strlen(dev->name) >= 32) {
		errno = E2BIG;
		return (-1);
	}
	db.type = (u_short) dev->type;
	db.space = dev->space;
	db.capacity = dev->capacity;
	db.state = dev->state;
	db.status = dev->status.bits;
	strcpy(db.name, dev->name);
	strcpy(db.vsn, dev->vsn);
	memcpy(buf, &db, bufsize);
	shmdt((char *) master_shm.shared_memory);
	return (0);
}

int
sam_ndevstat(
	    ushort_t eq,
	    struct sam_ndevstat * buf,
	    size_t bufsize)
{
	struct dev_ent *dev;
	dev_ptr_tbl_t  *dev_tbl;
	shm_alloc_t	master_shm;
	shm_ptr_tbl_t  *shm_ptr_tbl;
	struct sam_ndevstat db;

	if (bufsize < sizeof (db)) {
		errno = EINVAL;
		return (-1);
	}

	/*
	 * Access SAM-FS shared memory segment.
	 */
	if ((master_shm.shmid = shmget(SHM_MASTER_KEY, 0, 0)) < 0) {
#ifdef DEBUG
		fprintf(stderr, "Unable to find master shared memory segment.\n");
#endif				/* DEBUG */
		return (-1);
	}
	if ((master_shm.shared_memory =
		shmat(master_shm.shmid, NULL, 0)) == (void *)-1) {
#ifdef DEBUG
		fprintf(stderr, "Unable to attach master shared memory segment.\n");
#endif				/* DEBUG */
		return (-1);
	}
	shm_ptr_tbl = (shm_ptr_tbl_t *)master_shm.shared_memory;
	if (strcmp(shm_ptr_tbl->shm_block.segment_name, SAM_SEGMENT_NAME) != 0) {
#ifdef DEBUG
		fprintf(stderr, "Master shared memory segment name incorrect.\n");
#endif				/* DEBUG */
		shmdt((char *) master_shm.shared_memory);
		errno = ENOENT;
		return (-1);
	}
	dev_tbl = (dev_ptr_tbl_t *)
		SHM_REF_ADDR(shm_ptr_tbl->dev_table);
	if ((int) eq > dev_tbl->max_devices) {
		shmdt((char *) master_shm.shared_memory);
		errno = ENODEV;
		return (-1);
	}
	dev = (dev_ent_t *)SHM_REF_ADDR(dev_tbl->d_ent[eq]);
	if (dev == NULL) {
		shmdt((char *) master_shm.shared_memory);
		errno = ENODEV;
		return (-1);
	}
	db.type = (u_short) dev->type;
	db.space = dev->space;
	db.capacity = dev->capacity;
	db.state = dev->state;
	db.status = dev->status.bits;
	strcpy(db.name, dev->name);
	strcpy(db.vsn, dev->vsn);
	memcpy(buf, &db, bufsize);
	shmdt((char *) master_shm.shared_memory);
	return (0);
}
