/* @(#)sense.c	1.3 02/09/26 Copyright 2001 J. Schilling */
#ifndef lint
static	char sccsid[] =
	"@(#)sense.c	1.3 02/09/26 Copyright 2001 J. Schilling";
#endif
/*
 *	Copyright (c) 2001 J. Schilling
 */
/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING.  If not, write to
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <mconfig.h>
#include <stdio.h>
#include <stdxlib.h>
#include <unixstd.h>
#include <strdefs.h>
#include <schily.h>
#include <standard.h>

#include <utypes.h>
#include <btorder.h>
#include <scg/scgcmd.h>
#include <scg/scsidefs.h>
#include <scg/scsireg.h>
#include <scg/scsitransp.h>

#include "cdrecord.h"
#include "scgcheck.h"

extern	char	*buf;			/* The transfer buffer */
extern	long	bufsize;		/* The size of the transfer buffer */

extern	FILE	*logfile;
extern	char	unavail[];

LOCAL	BOOL	inq_nofail = FALSE;


EXPORT	void	sensetest	__PR((SCSI *scgp));
LOCAL	int	sensecount	__PR((SCSI *scgp, int sensecnt));
LOCAL	int	badinquiry	__PR((SCSI *scgp, caddr_t bp, int cnt, int sensecnt));
LOCAL	int	bad_unit_ready	__PR((SCSI *scgp, int sensecnt));

EXPORT void
sensetest(scgp)
	SCSI	*scgp;
{
	char	abuf[2];
	int	ret;
	int	sense_count = 0;
	BOOL	passed = TRUE;

	printf("Ready to start test for failing command? Enter <CR> to continue: ");
	fprintf(logfile, "**********> Testing for failed SCSI command.\n");
	flushit();
	(void)getline(abuf, sizeof(abuf));
/*	scgp->verbose++;*/
	fillbytes(buf, sizeof(struct scsi_inquiry), '\0');
	fillbytes((caddr_t)scgp->scmd, sizeof(*scgp->scmd), '\0');
	ret = badinquiry(scgp, buf, sizeof(struct scsi_inquiry), CCS_SENSE_LEN);
	scg_vsetup(scgp);
	scg_errfflush(scgp, logfile);
	if (ret >= 0 || !scg_cmd_err(scgp)) {
		inq_nofail = TRUE;
		printf("Inquiry did not fail.\n");
		fprintf(logfile, "Inquiry did not fail.\n");
		printf("This may be because the firmware in your drive is buggy.\n");
		printf("If the current drive is not a CD-ROM drive please restart\n");
		printf("the test utility. Otherwise remove any medium from the drive.\n");
		printf("Ready to start test for failing command? Enter <CR> to continue: ");
		flushit();
		(void)getline(abuf, sizeof(abuf));
		ret = test_unit_ready(scgp);
		if (ret >= 0 || !scg_cmd_err(scgp)) {
			scsi_unload(scgp, (cdr_t *)0);
			printf("Test Unit Ready did not fail.\n");
			printf("Ready to eject tray? Enter <CR> to continue: ");
			flushit();
			(void)getline(abuf, sizeof(abuf));
			ret = test_unit_ready(scgp);
		}
	}
	scg_vsetup(scgp);
	scg_errfflush(scgp, logfile);
/*	scgp->verbose--;*/
	if (ret < 0 &&
	    scgp->scmd->error == SCG_NO_ERROR &&
	    scgp->scmd->ux_errno != 0 &&
	    *(Uchar *)&scgp->scmd->scb != 0) {
		printf("----------> SCSI failed command test PASSED\n");
		fprintf(logfile, "----------> SCSI failed command test PASSED\n");
	} else {
		if (ret >= 0) {
			printf("---------->	scg_cmd() returns not -1 (%d)\n", ret);
			fprintf(logfile, "---------->	scg_cmd() returns not -1 (%d)\n", ret);
		}
		if (scgp->scmd->error != SCG_NO_ERROR) {
			printf("---------->	SCSI Transport return != SCG_NO_ERROR (%d)\n", scgp->scmd->error);
			fprintf(logfile, "---------->	SCSI Transport return != SCG_NO_ERROR (%d)\n", scgp->scmd->error);
		}
		if (scgp->scmd->ux_errno == 0) {
			printf("---------->	UNIX errno set to 0\n");
			fprintf(logfile, "---------->	UNIX errno set to 0\n");
		}
		if (*(Uchar *)&scgp->scmd->scb == 0) {
			printf("---------->	SCSI status byte set to 0 (0x%x)\n", *(Uchar *)&scgp->scmd->scb & 0xFF);
			fprintf(logfile, "---------->	SCSI status byte set to 0 (0x%x)\n", *(Uchar *)&scgp->scmd->scb & 0xFF);
		}
		printf("----------> SCSI failed command test FAILED\n");
		fprintf(logfile, "----------> SCSI failed command test FAILED\n");
	}


	printf("Ready to start test for sense data count? Enter <CR> to continue: ");
	fprintf(logfile, "**********> Testing for SCSI sense data count.\n");
	flushit();
	(void)getline(abuf, sizeof(abuf));
	printf("Testing if at least CCS_SENSE_LEN (%d) is supported...\n", CCS_SENSE_LEN);
	fprintf(logfile, "**********> Testing if at least CCS_SENSE_LEN (%d) is supported...\n", CCS_SENSE_LEN);
	ret = sensecount(scgp, CCS_SENSE_LEN);
	if (ret > sense_count)
		sense_count = ret;
	if (ret == CCS_SENSE_LEN) {
		printf("---------->	Wanted %d sense bytes got it.\n", CCS_SENSE_LEN);
		fprintf(logfile, "---------->	Wanted %d sense bytes got it.\n", CCS_SENSE_LEN);
	}
	if (ret != CCS_SENSE_LEN) {
		printf("---------->	Minimum standard (CCS) sense length failed\n");
		printf("---------->	Wanted %d sense bytes got (%d)\n", CCS_SENSE_LEN, ret);
		fprintf(logfile, "---------->	Minimum standard (CCS) sense length failed\n");
		fprintf(logfile, "---------->	Wanted %d sense bytes got (%d)\n", CCS_SENSE_LEN, ret);
	}
	if (ret != scgp->scmd->sense_count) {
		passed = FALSE;
		printf("---------->	Libscg says %d sense bytes but got (%d)\n", scgp->scmd->sense_count, ret);
		fprintf(logfile, "---------->	Libscg says %d sense bytes but got (%d)\n", scgp->scmd->sense_count, ret);
	}
	printf("Testing for %d bytes of sense data...\n", SCG_MAX_SENSE);
	fprintf(logfile, "**********> Testing for %d bytes of sense data...\n", SCG_MAX_SENSE);
	ret = sensecount(scgp, SCG_MAX_SENSE);
	if (ret > sense_count)
		sense_count = ret;
	if (ret == SCG_MAX_SENSE) {
		printf("---------->	Wanted %d sense bytes got it.\n", SCG_MAX_SENSE);
		fprintf(logfile, "---------->	Wanted %d sense bytes got it.\n", SCG_MAX_SENSE);
	}
	if (ret != SCG_MAX_SENSE) {
		printf("---------->	Wanted %d sense bytes got (%d)\n", SCG_MAX_SENSE, ret);
		fprintf(logfile, "---------->	Wanted %d sense bytes got (%d)\n", SCG_MAX_SENSE, ret);
	}
	if (ret != scgp->scmd->sense_count) {
		passed = FALSE;
		printf("---------->	Libscg says %d sense bytes but got (%d)\n", scgp->scmd->sense_count, ret);
		fprintf(logfile, "---------->	Libscg says %d sense bytes but got (%d)\n", scgp->scmd->sense_count, ret);
	}

	printf("----------> Got a maximum of %d sense bytes\n", sense_count);
	fprintf(logfile, "----------> Got a maximum of %d sense bytes\n", sense_count);
	if (passed && sense_count >= CCS_SENSE_LEN) {
		printf("----------> SCSI sense count test PASSED\n");
		fprintf(logfile, "----------> SCSI sense count test PASSED\n");
	} else {
		printf("----------> SCSI sense count test FAILED\n");
		fprintf(logfile, "----------> SCSI sense count test FAILED\n");
	}
}

LOCAL int
sensecount(scgp, sensecnt)
	SCSI	*scgp;
	int	sensecnt;
{
	int	maxcnt;
	int	i;
	Uchar	*p;

	if (sensecnt > SCG_MAX_SENSE)
		sensecnt = SCG_MAX_SENSE;
		
/*	scgp->verbose++;*/
	scgp->silent++;
	fillbytes(buf, sizeof(struct scsi_inquiry), '\0');
	fillbytes((caddr_t)scgp->scmd, sizeof(*scgp->scmd), '\0');
	fillbytes((caddr_t)scgp->scmd->u_sense.cmd_sense, sensecnt, 0x00);
	if (inq_nofail)
		bad_unit_ready(scgp, sensecnt);
	else
		badinquiry(scgp, buf, sizeof(struct scsi_inquiry), sensecnt);
	scg_prbytes("Sense Data:", (Uchar *)scgp->scmd->u_sense.cmd_sense, sensecnt);
	scg_fprbytes(logfile, "Sense Data:", (Uchar *)scgp->scmd->u_sense.cmd_sense, sensecnt);
	p = (Uchar *)scgp->scmd->u_sense.cmd_sense;
	for (i=sensecnt-1; i >= 0; i--) {
		if (p[i] != 0x00) {
			break;
		}
	}
	i++;
	maxcnt = i;
printf("%d %d %d\n", sensecnt, scgp->scmd->sense_count, maxcnt);

	fillbytes(buf, sizeof(struct scsi_inquiry), '\0');
	fillbytes((caddr_t)scgp->scmd, sizeof(*scgp->scmd), '\0');
	fillbytes((caddr_t)scgp->scmd->u_sense.cmd_sense, sensecnt, 0xFF);
	if (inq_nofail)
		bad_unit_ready(scgp, sensecnt);
	else
		badinquiry(scgp, buf, sizeof(struct scsi_inquiry), sensecnt);
	scg_prbytes("Sense Data:", (Uchar *)scgp->scmd->u_sense.cmd_sense, sensecnt);
	scg_fprbytes(logfile, "Sense Data:", (Uchar *)scgp->scmd->u_sense.cmd_sense, sensecnt);
	p = (Uchar *)scgp->scmd->u_sense.cmd_sense;
	for (i=sensecnt-1; i >= 0; i--) {
		if (p[i] != 0xFF) {
			break;
		}
	}
	i++;
	if (i > maxcnt)
		maxcnt = i;
printf("%d %d %d\n", sensecnt, scgp->scmd->sense_count, maxcnt);

/*	scgp->verbose--;*/
	scgp->silent--;
/*	scg_vsetup(scgp);*/
/*	scg_errfflush(scgp, logfile);*/

	return (i);
}

LOCAL int
badinquiry(scgp, bp, cnt, sensecnt)
	SCSI	*scgp;
	caddr_t	bp;
	int	cnt;
	int	sensecnt;
{
	register struct	scg_cmd	*scmd = scgp->scmd;

/*	fillbytes(bp, cnt, '\0');*/
/*	fillbytes((caddr_t)scmd, sizeof(*scmd), '\0');*/
	scmd->addr = bp;
	scmd->size = cnt;
	scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
	scmd->cdb_len = SC_G0_CDBLEN;
/*	scmd->sense_len = CCS_SENSE_LEN;*/
	scmd->sense_len = sensecnt;
	scmd->cdb.g0_cdb.cmd = SC_INQUIRY;
	scmd->cdb.g0_cdb.lun = scg_lun(scgp);
	scmd->cdb.g0_cdb.count = cnt;

scmd->cdb.cmd_cdb[3] = 0xFF;
	
	scgp->cmdname = "inquiry";

	if (scg_cmd(scgp) < 0)
		return (-1);
	if (scgp->verbose)
		scg_prbytes("Inquiry Data   :", (Uchar *)bp, cnt - scg_getresid(scgp));
	return (0);
}

LOCAL int
bad_unit_ready(scgp, sensecnt)
	SCSI	*scgp;
	int	sensecnt;
{
	register struct	scg_cmd	*scmd = scgp->scmd;

/*	fillbytes((caddr_t)scmd, sizeof(*scmd), '\0');*/
	scmd->addr = (caddr_t)0;
	scmd->size = 0;
	scmd->flags = SCG_DISRE_ENA | (scgp->silent ? SCG_SILENT:0);
	scmd->cdb_len = SC_G0_CDBLEN;
	scmd->sense_len = sensecnt;
	scmd->cdb.g0_cdb.cmd = SC_TEST_UNIT_READY;
	scmd->cdb.g0_cdb.lun = scg_lun(scgp);
	
	scgp->cmdname = "test unit ready";

	return (scg_cmd(scgp));
}
