/* @(#)acb4000.c	1.20 00/05/07 Copyright 1989 J. Schilling */
#ifndef lint
static	char sccsid[] =
	"@(#)acb4000.c	1.20 00/05/07 Copyright 1989 J. Schilling";
#endif
/*
 *	Routines for ADAPTEC 40xx & 5000 series.
 *
 *	Copyright (c) 1989 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 <sys/param.h>
#include <standard.h>
#include <schily.h>

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

#include "scsicmds.h"
#include "fmt.h"

EXPORT	int	acbdev 			__PR((SCSI *scgp));
EXPORT	BOOL	get_acb4000defaults	__PR((SCSI *scgp, struct disk *));
EXPORT	BOOL	set_acb4000params	__PR((SCSI *scgp, struct disk *));

EXPORT
int acbdev(scgp)
	SCSI	*scgp;
{
	struct scsi_mode_data	md;
	long	blocksize;
	long	sectorcnt;

	fillbytes((caddr_t)&md, sizeof(md), '\0');

	if (mode_sense(scgp, (u_char *)&md, 24, 0, 0) < 0)
		return (scgp->dev);

	blocksize = a_to_u_3_byte(md.blockdesc.lblen);
	sectorcnt = md.pagex.acb.sect_per_trk;
if (scgp->silent < 2)
printf("blocksize: %ld sectorcnt: %ld\n", blocksize, sectorcnt);

	/*
	 * Wenn 'blocksize' und 'sectorcnt'
	 * auf ihren Defaultwerten sind, dann läßt sich der
	 * Typ des Kontrollers nicht bestimmen.
	 */
	if (blocksize == 256 && sectorcnt == 32)
		return (scgp->dev);

	if (blocksize * sectorcnt > 10416) /* 5MB/s / 60rps / 8bit/Byte */
		return (DEV_ACB4070);

	if (md.pagex.acb.hard_sec && (scgp->dev==DEV_ACB40X0 || scgp->dev==DEV_ACB4000))
		return (DEV_ACB4010);

	return (DEV_ACB4000);
}

EXPORT
BOOL get_acb4000defaults(scgp, dp)
	SCSI		*scgp;
	struct disk	*dp;
{
	struct scsi_mode_data	md;
	long	tmp;

	fillbytes((caddr_t)&md, sizeof(md), '\0');

	(void)test_unit_ready(scgp);
	if (mode_sense(scgp, (u_char *)&md, 24, 0, 0) < 0)
		return (FALSE);

	tmp = a_to_u_3_byte(md.blockdesc.lblen);
	if (dp->secsize < 0 && tmp != 0)
		dp->secsize = tmp;

	tmp = a_to_u_2_byte(md.pagex.acb.ncyl);
	if (dp->pcyl < 0 && tmp != 0)
		dp->pcyl = tmp;
	if (dp->lpcyl < 0 && tmp != 0)
		dp->lpcyl = tmp;

	tmp = md.pagex.acb.nhead;
	if (dp->nhead < 0 && tmp != 0)
		dp->nhead = tmp;

	tmp = a_to_u_2_byte(md.pagex.acb.start_red_wcurrent);
	if (dp->reduced_curr < 0 && tmp != 0)
		dp->reduced_curr = tmp;

	tmp = a_to_u_2_byte(md.pagex.acb.start_precomp);
	if (dp->write_precomp < 0 && tmp != 0)
		dp->write_precomp = tmp;

	tmp = md.pagex.acb.step_rate;
	if (dp->step_rate < 0 && tmp != 0)
		dp->step_rate = tmp;

	tmp = md.pagex.acb.sect_per_trk;
	if (dp->spt < 0 && tmp != 0)
		dp->spt = tmp;

	return (TRUE);
}

EXPORT
BOOL set_acb4000params(scgp, dp)
	SCSI		*scgp;
	struct disk	*dp;
{
	struct scsi_mode_data	md;
	int	mode_len = 24;

	fillbytes((caddr_t)&md, sizeof(md), '\0');

	(void)test_unit_ready(scgp);
	if (mode_sense(scgp, (u_char *)&md, mode_len, 0, 0) < 0)
		return (FALSE);

	i_to_3_byte(md.blockdesc.nlblock, 0);
	i_to_3_byte(md.blockdesc.lblen, dp->secsize);
/*#ifdef	notneeded*/
	/*
	 * Listformat muß laut Handbuch bei softsektorierten Festplatten
	 * auf '1', in allen anderen Fällen auf '2' gesetzt werden.
	 *
	 * Es scheint aber nur die Anzahl der Bytes zu steuern, die bei
	 * einem MODE_SELECT entgegengenommen werden.
	 * Da wir über die korrekten Daten von MODE_SENSE verfügen,
	 * können wir auf diese Unterscheidung verzichten.
	 */
	if (md.pagex.acb.fixed_media == 1 && md.pagex.acb.hard_sec == 0) {
		md.pagex.acb.listformat = 1;
		mode_len = 22;
	} else {
		md.pagex.acb.listformat = 2;
	}
/*#endif*/
	i_to_2_byte(md.pagex.acb.ncyl, dp->pcyl);
	md.pagex.acb.nhead = dp->nhead;
	i_to_2_byte(md.pagex.acb.start_red_wcurrent, dp->reduced_curr);
	i_to_2_byte(md.pagex.acb.start_precomp, dp->write_precomp);
	md.pagex.acb.landing_zone = 0;
	md.pagex.acb.step_rate = dp->step_rate;
	md.pagex.acb.sect_per_trk = dp->spt;

	if (mode_select(scgp, (u_char *)&md, mode_len, 0, 0) < 0)
		return (FALSE);
	return (TRUE);
}
