/*
 *	scsi_error.h - SAM-FS generic scsi error interface.
 */

/*
 *    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
 */

#if !defined(_AML_SCSI_ERROR_H)
#define	_AML_SCSI_ERROR_H

#pragma ident "$Revision$"

#if defined(__cplusplus)
extern "C" {
#endif

/*
 * Message codes
 */

#define	MAN_INTER	1		/* Manual intervention reqired */
#define	POWER_ON	2		/* Power on detected */
#define	STOP_BUTTON	3		/* Stop button pressed */
#define	OFFLINE		4		/* Unit is offline */
#define	DOOR_OPEN	5		/* Door is open */
#define	SELF_FAILED	6		/* Self test failed */
#define	STANDBY		7		/* Standby mode */
#define	HARDWARE	8		/* fatal hardware error */
#define	PICKFAIL	9		/* Media pick failed */
#define	WRONG_MODE	10		/* Wrong mode */
#define	MEDIA_RESER	11		/* Media reserved by another */
#define	INCOMPATIBLE	12		/* Incompatible media */

#if defined(SCSI_ERRCODES)
char *scsi_errcode[] = {
	"",
	"Fatal hardware error, manual intervention required.",
	"Power on/reset.",
	"Stop button pressed.",
	"Unit is offline.",
	"Door is open.",
	"Self test failed.",
	"Unit is in standby.",
	"Fatal hardware error.",
	"Media pick failure.",
	"Changer is not in the correct mode.",
	"Media is reserved by another initiator.",
	"Incompatible media",
};
#else
extern char *scsi_errcode[];
#endif

/*
 * Definitions for general scsi error interface
 */

enum	sam_scsi_action {
	WAIT_READY = 1,		/* wait for ready (5 second sleep) retry */
	WAIT_READY_LONG,	/* wait for ready (10 second sleep) retry */
	WAIT_INIT,		/* wait ready then init and update element status */
	WAIT_INIT_AUDIT,	/* WAIT_INIT followed by audit */
	IGNORE,			/* Ignore and continue */
	D_ELE_FULL,		/* Destination element full */
	S_ELE_EMPTY,		/* Source element empty */
	NO_MEDIA,		/* Media not present */
	CLEANING_CART,		/* Cleaning cart is in drive */
	BAD_BARCODE,		/* barcode bad or unreadable */
	LOG_ABOVE_THIS,		/* All actions above this are logged */
	DOWN_EQU,		/* down equipment */
	DOWN_SUB_EQU,		/* For robot commands where the drive needs to be downed */
	CLR_TRANS_RET,		/* clear transports and retry */
	UPDT_ELEMS_RET,		/* Update elements and retry */
	REZERO,			/* rezero and retry */
	LOG_IGNORE,		/* log and retry */
	LONG_WAIT_LOG,		/* wait a long time (30 second) and retry */
	ILLREQ,			/* unknown illegal request */
	MARK_UNAVAIL,		/* make element unavailable */
	INCOMPATIBLE_MEDIA,	/* incompatible media */
	NOT_READY,		/* unit is not ready */
	BAD_MEDIA,		/* media is bad */
	WRITE_PROTECT,
	BLANK_CHECK,
	NEEDS_FORMATTING,	/* Media needs formatting */
	RETRIES_EXCEEDED,
	END_OF_LIST
};

typedef struct sam_scsi_err {
	u_char		sense_key;
	u_char		add_sense;
	u_char		add_sense_qual;
	u_short		message_code;			/* message to log */
	enum		sam_scsi_action	action;		/* recovery action */
}sam_scsi_err_t;

/*
 * For process_scsi_error (old form)
 */

#define	ERR_SCSI_LOG			1		/* log non fatel errors */
#define	ERR_SCSI_NOLOG			0		/* don't log errors */

#define	WAIT_TIME_FOR_READY		5		/* in seconds for WAIT_READY */
#define	WAIT_TIME_FOR_READY_LONG	10		/* in seconds for WAIT_READY_LOG */
#define	WAIT_TIME_FOR_LONG_WAIT_LOG	30		/* in seconds LONG_WAIT_LOG */

/*
 * These are non-retry-able give up errors
 */
#define	TUR_ERROR(_e)	(((_e) == NO_MEDIA) || ((_e) == DOWN_EQU) || ((_e) == ILLREQ) || \
						((_e) == INCOMPATIBLE_MEDIA) || ((_e) == NOT_READY) || \
						((_e) == BAD_MEDIA) || ((_e) == RETRIES_EXCEEDED))

/*
 * GENERIC_SCSI_ERROR_PROCESSING() - general code for most SCSI error processing
 *
 *	_un	(dev_ent_t *)
 *	_errtab				- error processing table to use
 *	_l				- log, !log
 *	_err				- variable where process_scsi_error() return value goes
 *	_added_more_time		- variable which defines whether we need to add more time on waits
 *	_retry				- retry counter
 *	_downeq				- code to execute on DOWN_EQU
 *	_illreq				- code to execute on ILLREQ
 *	_more_code			- any more code to execute
 */

#define	GENERIC_SCSI_ERROR_PROCESSING(_un, _errtab, _l, _err, _added_more_time, _retry, _downeq, _illreq, _more_code)	\
							{	\
								_err = (int)process_scsi_error(_un, _errtab, _l);	\
								switch ((enum sam_scsi_action)_err) {	\
	\
									case LONG_WAIT_LOG:	\
										sleep(WAIT_TIME_FOR_LONG_WAIT_LOG);	\
										continue;	\
   	\
									case WAIT_READY_LONG:	\
										sleep(abs(WAIT_TIME_FOR_READY_LONG - WAIT_TIME_FOR_READY));	\
									case WAIT_READY:	\
										if (_added_more_time == FALSE) {	\
											_retry += 60;	\
											_added_more_time = TRUE;	\
										}	\
										sleep(WAIT_TIME_FOR_READY);	\
	\
									default:	\
										break;	\
	\
									case IGNORE:	\
										break;	\
	\
									case ILLREQ:	\
										_illreq	\
	\
									case DOWN_EQU:	\
										_downeq	\
	\
									_more_code	\
								}	\
							}

/*
 * returned from process_scsi_error
 */

#define	ERR_SCSI_NOERROR	0x00				/* no error */
#define	ERR_SCSI_RECOVED	0x01				/* recovered error */
#define	ERR_SCSI_ILLREQ		0x02				/* Illegal request */
#define	ERR_SCSI_SRC_EMPTY	0x03				/* Source element empty */
#define	ERR_SCSI_DEST_FULL	0x04				/* Destination element full */
#define	ERR_SCSI_NO_MEDIA	0x05				/* No media */

#define	ERR_SCSI_ATTNBIT	0x400000			/* unit attention bit */
#define	ERR_SCSI_MEDIA_I  	(0x01 | ERR_SCSI_ATTNBIT) 	/* media imported */
#define	ERR_SCSI_MEDIA_E  	(0x02 | ERR_SCSI_ATTNBIT) 	/* media exported */
#define	ERR_SCSI_POWERON  	(0x03 | ERR_SCSI_ATTNBIT) 	/* power on */
#define	ERR_SCSI_MICROCODE 	(0x04 | ERR_SCSI_ATTNBIT) 	/* M-code changed */
#define	ERR_SCSI_OPERATOR  	(0x05 | ERR_SCSI_ATTNBIT) 	/* operator */
#define	ERR_SCSI_UNKNOWNUA 	(0x06 | ERR_SCSI_ATTNBIT) 	/* Unknown */

#define	ERR_SCSI_FATELERR	0x800000			/* above this is bad */
#define	ERR_SCSI_NOTREADY 	(0x01 | ERR_SCSI_FATELERR) 	/* not ready */
#define	ERR_SCSI_HARDWARE 	(0x02 | ERR_SCSI_FATELERR) 	/* Hardware */


#if defined(__cplusplus)
}
#endif

#endif /* !defined(_AML_SCSI_ERROR_H) */
