/*
 * Copyright (c) 1998,1999,2000
 *	Traakan, Inc., Los Altos, CA
 *	All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice unmodified, this list of conditions, and the following
 *    disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * Project:  NDMJOB
 * Ident:    $Id: $
 *
 * Description:
 *
 */


#include "smc_priv.h"


#define WITH(P,V,T)	{ T * V = (T *) P;
#define ENDWITH		}

int
smc_parse_volume_tag (
  struct smc_raw_volume_tag *raw,
  struct smc_volume_tag *vtag)
{
	int		i;

	bzero (vtag, sizeof *vtag);

	for (i = 31; i >= 0 && raw->volume_id[i] == ' '; i--)
		continue;

	for (; i >= 0; i--)
		vtag->volume_id[i] = raw->volume_id[i];

	vtag->volume_seq = SMC_GET2(raw->volume_seq);

	return 0;
}



int
smc_parse_element_status_data (
  char *	raw,
  unsigned	raw_len,
  struct smc_element_descriptor elem_desc[],
  unsigned	max_elem_desc)
{
	unsigned char *			p = (unsigned char *)raw;
	unsigned char *			raw_end = p + raw_len;
	unsigned int			n_elem = 0;

	bzero (elem_desc, sizeof elem_desc[0] * max_elem_desc);

	WITH(p, esdh, struct smc_raw_element_status_data_header)
		unsigned	byte_count = SMC_GET3(esdh->byte_count);

		if (raw_len > byte_count+8) {
			/* probably an error, but press on */
			raw_len = byte_count+8;
		}
		raw_end = p + raw_len;
	ENDWITH

	p += 8;

	while (p+8 < raw_end) {		/* +8 for sizeof *esph */
	    WITH(p, esph, struct smc_raw_element_status_page_header)
		unsigned	desc_size = SMC_GET2(esph->elem_desc_len);
		unsigned	byte_count = SMC_GET3(esph->byte_count);
		unsigned	elem_type = esph->element_type;
		unsigned char *	pgend = p + byte_count + 8;
		int		PVolTag = 0;
		int		AVolTag = 0;

		if (pgend > raw_end) {
			/* malformed, really, but punt */
			pgend = raw_end;
		}

		if (esph->flag1 & SMC_RAW_ESP_F1_PVolTag)
			PVolTag = 1;
		if (esph->flag1 & SMC_RAW_ESP_F1_AVolTag)
			AVolTag = 1;

		p += 8;

		for (;p + desc_size <= pgend; p += desc_size) {
		    struct smc_element_descriptor *edp;

		    if (n_elem >= max_elem_desc) {
			/* bust out */
			goto done;
		    }
		    edp = &elem_desc[n_elem++];
		    WITH (p, red, struct smc_raw_element_descriptor)
			unsigned char *p2;

			edp->element_type_code = elem_type;
			edp->element_address = SMC_GET2(red->element_address);
			edp->PVolTag = PVolTag;
			edp->AVolTag = AVolTag;
#define FLAG(RAWMEM,BIT,MEM) if (red->RAWMEM & BIT) edp->MEM = 1;
			FLAG(flags2, SMC_RAW_ED_F2_Full, Full);
			FLAG(flags2, SMC_RAW_ED_F2_ImpExp, ImpExp);
			FLAG(flags2, SMC_RAW_ED_F2_Except, Except);
			FLAG(flags2, SMC_RAW_ED_F2_Access, Access);
			FLAG(flags2, SMC_RAW_ED_F2_ExEnab, ExEnab);
			FLAG(flags2, SMC_RAW_ED_F2_InEnab, InEnab);

			edp->asc = red->asc;
			edp->ascq = red->ascq;

			edp->scsi_lun = red->flags6 & 7;
			FLAG(flags6, SMC_RAW_ED_F6_LU_valid, LU_valid);
			FLAG(flags6, SMC_RAW_ED_F6_ID_valid, ID_valid);
			FLAG(flags6, SMC_RAW_ED_F6_Not_bus, Not_bus);

			edp->scsi_sid = red->scsi_sid;

			FLAG(flags9, SMC_RAW_ED_F9_Invert, Invert);
			FLAG(flags9, SMC_RAW_ED_F9_SValid, SValid);
#undef FLAG

			edp->src_se_addr = SMC_GET2(red->src_se_addr);

			p2 = (unsigned char *) &red->primary_vol_tag;
			if (edp->PVolTag) {
				smc_parse_volume_tag ((void*)p2,
						&edp->primary_vol_tag);
				p2 += SMC_VOL_TAG_LEN;
			}
			if (edp->AVolTag) {
				smc_parse_volume_tag ((void*)p2,
						&edp->alternate_vol_tag);
				p2 += SMC_VOL_TAG_LEN;
			}
			p2 += 4;	/* resv84 */
			/* p2 ready for vendor_specific */
		    ENDWITH
		}
		p = pgend;
	    ENDWITH
	}

  done:
	return n_elem;
}



int
smc_parse_element_address_assignment (
  struct smc_raw_element_address_assignment_page *raw,
  struct smc_element_address_assignment *eaa)
{
	eaa->mte_addr  = SMC_GET2(raw->mte_addr);
	eaa->mte_count = SMC_GET2(raw->mte_count);
	eaa->se_addr   = SMC_GET2(raw->se_addr);
	eaa->se_count  = SMC_GET2(raw->se_count);
	eaa->iee_addr  = SMC_GET2(raw->iee_addr);
	eaa->iee_count = SMC_GET2(raw->iee_count);
	eaa->dte_addr  = SMC_GET2(raw->dte_addr);
	eaa->dte_count = SMC_GET2(raw->dte_count);

	return 0;
}

