xref: /haiku/headers/os/drivers/bus/SCSI.h (revision 7746364088560b850a16ca95ee6441cf50774d6f)
10d59a3d2SAxel Dörfler /*
2368167edSAxel Dörfler  * Copyright 2004-2008, Haiku, Inc. All RightsReserved.
3b83a8af4SAxel Dörfler  * Copyright 2002/03, Thomas Kurschel. All rights reserved.
4c9fc73fcSAxel Dörfler  *
5b83a8af4SAxel Dörfler  * Distributed under the terms of the MIT License.
60d59a3d2SAxel Dörfler  */
76be1e37dSAxel Dörfler #ifndef _SCSI_BUSMANAGER_H
86be1e37dSAxel Dörfler #define _SCSI_BUSMANAGER_H
90d59a3d2SAxel Dörfler 
100d59a3d2SAxel Dörfler /*
110d59a3d2SAxel Dörfler 	SCSI bus manager interface
120d59a3d2SAxel Dörfler 
130d59a3d2SAxel Dörfler 	The bus manager interface is _based_ on CAM, but I've modified it because :-
140d59a3d2SAxel Dörfler 	- HBA engine, target mode and queue freezing (and probably other features)
150d59a3d2SAxel Dörfler 	  aren't supported (at least the first two aren't supported by linux too ;)
160d59a3d2SAxel Dörfler 	- Asynchronous events aren't supported (no OS/driver I know uses them)
170d59a3d2SAxel Dörfler 	- P/T/L was defined by number not by handle, requiring many redundant tests
180d59a3d2SAxel Dörfler 	  and thus making adding/removing of devices/busses very hard, especially if
190d59a3d2SAxel Dörfler 	  PnP is to be supported
200d59a3d2SAxel Dörfler 	- single entry system as proposed by CAM involves extra tests and overhead
210d59a3d2SAxel Dörfler 	  because of generalized data structure
220d59a3d2SAxel Dörfler 
230d59a3d2SAxel Dörfler 
240d59a3d2SAxel Dörfler 	For peripheral driver writers:
250d59a3d2SAxel Dörfler 
260d59a3d2SAxel Dörfler 	Something about requests involving data transfer: you can either specify
270d59a3d2SAxel Dörfler 	the virtual address in <data> of CCB (in which case it must be continuous),
280d59a3d2SAxel Dörfler 	or store a pointer to a S/G list that contains physical addresses in
296be1e37dSAxel Dörfler 	<sg_list>/<sg_count>. If <sg_list> is non-Null, <data> is ignored.
300d59a3d2SAxel Dörfler 	The S/G list must be in kernel space because the request can be executed
310d59a3d2SAxel Dörfler 	in a different thread context. This is also the	reason why the S/G list has
320d59a3d2SAxel Dörfler 	to contain physical addresses. For obvious reason, the data buffer specified
330d59a3d2SAxel Dörfler 	by <sg_list> must be locked, but <data> doesn't need to be.
340d59a3d2SAxel Dörfler 
350d59a3d2SAxel Dörfler 	You can either execute the request synchronously ("sync_io") or
360d59a3d2SAxel Dörfler 	asynchronously ("async_io"; you have to acquire <completion_sem> to find
370d59a3d2SAxel Dörfler 	out when the request is finished). In the first case you can use either
380d59a3d2SAxel Dörfler 	<data> or <sg_list>, in the latter <sg_list> only.
390d59a3d2SAxel Dörfler 
400d59a3d2SAxel Dörfler 	The SCSI bus manager takes care that the controller can access the data
410d59a3d2SAxel Dörfler 	via DMA by copying it into a buffer if necessary. For the paging path,
420d59a3d2SAxel Dörfler 	this can lead to problems (if the system writes a page to disk and the SCSI
430d59a3d2SAxel Dörfler 	bus manager has to allocate a buffer during execution you are in trouble),
440d59a3d2SAxel Dörfler 	therefore the blk_man takes care that is not necessary for reads/writes.
450d59a3d2SAxel Dörfler 	To safe some microseconds, you should set the SCSI_DMA_SAFE flag for these
460d59a3d2SAxel Dörfler 	requests, so the SCSI bus manager ommittes the test.
470d59a3d2SAxel Dörfler 
480d59a3d2SAxel Dörfler 	Effectively, using synchronous execution and specifying the address via
490d59a3d2SAxel Dörfler 	<data> is a safe bet.
500d59a3d2SAxel Dörfler 
510d59a3d2SAxel Dörfler 
520d59a3d2SAxel Dörfler 	For SIM writers:
530d59a3d2SAxel Dörfler 
540d59a3d2SAxel Dörfler 	Requests sent by peripheral drivers are forwarded to the <scsi_io> entry
550d59a3d2SAxel Dörfler 	of the SIM. You should return as soon as some waiting is required.
560d59a3d2SAxel Dörfler 	Usually, the controller raises an IRQ when a request can be continued
570d59a3d2SAxel Dörfler 	or is finished. As interrupt handlers must be as fast as possible, you
580d59a3d2SAxel Dörfler 	can schedule a DPC in the handler (<schedule_dpc>) which executed by a
590d59a3d2SAxel Dörfler 	high priority service thread that is spawned by the SCSI bus manager
600d59a3d2SAxel Dörfler 	for each bus. This service thread also takes care to submit waiting
610d59a3d2SAxel Dörfler 	requests.
620d59a3d2SAxel Dörfler 
630d59a3d2SAxel Dörfler 	You can specify a maximum number of concurrent requests per bus via
640d59a3d2SAxel Dörfler 	path_inquiry (<hba_queue_size>) for the bus. The device limit is
650d59a3d2SAxel Dörfler 	determined via INQUIRY. If you need a lower/dynamic limit, you can refuse
660d59a3d2SAxel Dörfler 	a request by <requeue>. If <bus_overflow> is true, no further requests
670d59a3d2SAxel Dörfler 	to the bus will be sent, if <bus_overflow> is false, no further requests
680d59a3d2SAxel Dörfler 	to the device will be sent. To terminate the overflow condition, call
690d59a3d2SAxel Dörfler 	<cont_send_device>/<cont_send_bus>. It also terminated when a request
700d59a3d2SAxel Dörfler 	for the bus/device is finished via <finished> or <resubmit>.
710d59a3d2SAxel Dörfler 	Because of the asynchronous nature,	requests may still arrive after the
720d59a3d2SAxel Dörfler 	overflow condition being signalled, so you should add a safety test to
730d59a3d2SAxel Dörfler 	<scsi_io>.
740d59a3d2SAxel Dörfler 
750d59a3d2SAxel Dörfler 	If a problem occurs during execution, you can ask for a restart via
760d59a3d2SAxel Dörfler 	<resubmit>. The request in question will be submitted as soon as possible.
770d59a3d2SAxel Dörfler 
780d59a3d2SAxel Dörfler 	If you want to be not disturbed, you can block further requests via
790d59a3d2SAxel Dörfler 	<block_bus>/<block_device>. As said above, you must have a safety test
800d59a3d2SAxel Dörfler 	at <scsi_io> though.
810d59a3d2SAxel Dörfler 
820d59a3d2SAxel Dörfler 	If the SIM uses a non-SCSI protocol, it can ask the SCSI bus manager
830d59a3d2SAxel Dörfler 	to emulate unsupported SCSI commands by translating them other (supported)
840d59a3d2SAxel Dörfler 	commands. The bus manager calls <get_restriction> during detection for
850d59a3d2SAxel Dörfler 	each device, setting <is_atapi> on return makes the bus manager translate
860d59a3d2SAxel Dörfler 	READ6/WRITE6 commands to READ10/WRITE10 commands, MODE REQUEST6/SENSE6
870d59a3d2SAxel Dörfler 	to MODE REQUEST10/SENSE10 and fix the version fields of INQUIRY results,
880d59a3d2SAxel Dörfler 	so ATAPI devices can be used like standard SCSI devices. Further, the
890d59a3d2SAxel Dörfler 	SCSI bus manager can emulate auto-sense by executing a REQUEST SENSE
900d59a3d2SAxel Dörfler 	if <subsys_status> is SCSI_REQ_CMP_ERR and <device_status> is
91f0d174e9SMarcus Overhagen 	SCSI_STATUS_CHECK_CONDITION when a request is finished. This emulation
920d59a3d2SAxel Dörfler 	may be enhanced/generalized in the future.
930d59a3d2SAxel Dörfler */
940d59a3d2SAxel Dörfler 
950d59a3d2SAxel Dörfler 
960d59a3d2SAxel Dörfler #include <KernelExport.h>
97*77463640SAugustin Cavalier 
98*77463640SAugustin Cavalier #ifdef _KERNEL_MODE
99*77463640SAugustin Cavalier #include <condition_variable.h>
1000d59a3d2SAxel Dörfler #include <device_manager.h>
101*77463640SAugustin Cavalier #endif
1020d59a3d2SAxel Dörfler 
1030d59a3d2SAxel Dörfler 
1040d59a3d2SAxel Dörfler typedef struct scsi_bus_info *scsi_bus;
1050d59a3d2SAxel Dörfler typedef struct scsi_device_info *scsi_device;
1060d59a3d2SAxel Dörfler 
1070d59a3d2SAxel Dörfler 
108*77463640SAugustin Cavalier #if defined(__cplusplus) && defined(_KERNEL_MODE)
1090d59a3d2SAxel Dörfler // structure of one scsi i/o CCB (command control block)
1106be1e37dSAxel Dörfler typedef struct scsi_ccb {
1110d59a3d2SAxel Dörfler 	struct scsi_ccb *next, *prev;	// internal
1120d59a3d2SAxel Dörfler 
1130d59a3d2SAxel Dörfler 	uchar		subsys_status;		// Returned subsystem status
1140d59a3d2SAxel Dörfler 	uchar		device_status;		// Returned scsi device status
1150d59a3d2SAxel Dörfler 
1160d59a3d2SAxel Dörfler 	uchar		path_id;			// Path ID for the request
1170d59a3d2SAxel Dörfler 	uchar		target_id;			// Target device ID
1180d59a3d2SAxel Dörfler 	uchar		target_lun;			// Target LUN number
1190d59a3d2SAxel Dörfler 	uint32		flags;				// Flags for operation of the subsystem
1200d59a3d2SAxel Dörfler 
121*77463640SAugustin Cavalier 	// notified after asynchronous execution of request
122*77463640SAugustin Cavalier 	ConditionVariable completion_cond;
1230d59a3d2SAxel Dörfler 
124*77463640SAugustin Cavalier #define SCSI_MAX_CDB_SIZE 16
1250d59a3d2SAxel Dörfler 	uint8		cdb[SCSI_MAX_CDB_SIZE];  // command data block
1266be1e37dSAxel Dörfler 	uchar		cdb_length;			// length of command in bytes
1270d59a3d2SAxel Dörfler 	int64		sort;				// value of command to sort on (<0 means n/a)
1280d59a3d2SAxel Dörfler 	bigtime_t	timeout;			// timeout - 0 = use default
1290d59a3d2SAxel Dörfler 
1300d59a3d2SAxel Dörfler 	uchar		*data;				// pointer to data
1316be1e37dSAxel Dörfler 	const physical_entry *sg_list;	// scatter/gather list
1326be1e37dSAxel Dörfler 	uint16		sg_count;			// number of S/G entries
1336be1e37dSAxel Dörfler 	uint32		data_length;		// length of data
1340d59a3d2SAxel Dörfler 	int32		data_resid;			// data transfer residual length: 2's comp
13524593e2cSAxel Dörfler 	void		*io_operation;
1360d59a3d2SAxel Dörfler 
137*77463640SAugustin Cavalier #define SCSI_MAX_SENSE_SIZE	64
1380d59a3d2SAxel Dörfler 	uchar		sense[SCSI_MAX_SENSE_SIZE]; // autosense data
1390d59a3d2SAxel Dörfler 	uchar		sense_resid;		// autosense resid length: 2's comp
1400d59a3d2SAxel Dörfler 
1410d59a3d2SAxel Dörfler 	// private
1420d59a3d2SAxel Dörfler 	bool		ordered : 1;		// request cannot overtake/be overtaken by others
1430d59a3d2SAxel Dörfler 	bool		buffered : 1;		// data is buffered to make it DMA safe
1440d59a3d2SAxel Dörfler 	bool		emulated : 1;		// command is executed as part of emulation
1450d59a3d2SAxel Dörfler 
1460d59a3d2SAxel Dörfler 	scsi_bus	bus;				// associated bus
1470d59a3d2SAxel Dörfler 	scsi_device	device;				// associated device
1480d59a3d2SAxel Dörfler 	struct dma_buffer *dma_buffer;	// used dma buffer, or NULL
1490d59a3d2SAxel Dörfler 	uchar 		state;				// bus manager state
1500d59a3d2SAxel Dörfler 
1510d59a3d2SAxel Dörfler 	// original data before command emulation was applied
1520d59a3d2SAxel Dörfler 	uint8		orig_cdb[SCSI_MAX_CDB_SIZE];
1536be1e37dSAxel Dörfler 	uchar		orig_cdb_length;
1540d59a3d2SAxel Dörfler 	const physical_entry *orig_sg_list;
1556be1e37dSAxel Dörfler 	uint16		orig_sg_count;
1566be1e37dSAxel Dörfler 	uint32		orig_data_length;
1570d59a3d2SAxel Dörfler } scsi_ccb;
158*77463640SAugustin Cavalier #else
159*77463640SAugustin Cavalier typedef struct scsi_ccb scsi_ccb;
160*77463640SAugustin Cavalier #endif
1610d59a3d2SAxel Dörfler 
1620d59a3d2SAxel Dörfler 
1630d59a3d2SAxel Dörfler // Defines for the subsystem status field
1640d59a3d2SAxel Dörfler 
1650d59a3d2SAxel Dörfler #define	SCSI_REQ_INPROG			0x00	/* request is in progress */
1660d59a3d2SAxel Dörfler #define SCSI_REQ_CMP 			0x01	/* request completed w/out error */
1670d59a3d2SAxel Dörfler #define SCSI_REQ_ABORTED		0x02	/* request aborted by the host */
1680d59a3d2SAxel Dörfler #define SCSI_UA_ABORT			0x03	/* Unable to Abort request */
1690d59a3d2SAxel Dörfler #define SCSI_REQ_CMP_ERR		0x04	/* request completed with an err */
1700d59a3d2SAxel Dörfler #define SCSI_BUSY				0x05	/* subsystem is busy */
1710d59a3d2SAxel Dörfler #define SCSI_REQ_INVALID		0x06	/* request is invalid */
1720d59a3d2SAxel Dörfler #define SCSI_PATH_INVALID		0x07	/* Path ID supplied is invalid */
1730d59a3d2SAxel Dörfler #define SCSI_DEV_NOT_THERE		0x08	/* SCSI device not installed/there */
1740d59a3d2SAxel Dörfler #define SCSI_UA_TERMIO			0x09	/* Unable to Terminate I/O req */
1750d59a3d2SAxel Dörfler #define SCSI_SEL_TIMEOUT		0x0A	/* Target selection timeout */
1760d59a3d2SAxel Dörfler #define SCSI_CMD_TIMEOUT		0x0B	/* Command timeout */
1770d59a3d2SAxel Dörfler #define SCSI_MSG_REJECT_REC		0x0D	/* Message reject received */
1780d59a3d2SAxel Dörfler #define SCSI_SCSI_BUS_RESET		0x0E	/* SCSI bus reset sent/received */
1790d59a3d2SAxel Dörfler #define SCSI_UNCOR_PARITY		0x0F	/* Uncorrectable parity err occurred */
1800d59a3d2SAxel Dörfler #define SCSI_AUTOSENSE_FAIL		0x10	/* Autosense: Request sense cmd fail */
1810d59a3d2SAxel Dörfler #define SCSI_NO_HBA				0x11	/* No HBA detected Error */
1820d59a3d2SAxel Dörfler #define SCSI_DATA_RUN_ERR		0x12	/* Data overrun/underrun error */
1830d59a3d2SAxel Dörfler #define SCSI_UNEXP_BUSFREE		0x13	/* Unexpected BUS free */
1840d59a3d2SAxel Dörfler #define SCSI_SEQUENCE_FAIL		0x14	/* Target bus phase sequence failure */
1850d59a3d2SAxel Dörfler #define SCSI_PROVIDE_FAIL		0x16	/* Unable to provide requ. capability */
1860d59a3d2SAxel Dörfler #define SCSI_BDR_SENT			0x17	/* A SCSI BDR msg was sent to target */
1870d59a3d2SAxel Dörfler #define SCSI_REQ_TERMIO			0x18	/* request terminated by the host */
1880d59a3d2SAxel Dörfler #define SCSI_HBA_ERR			0x19	/* Unrecoverable host bus adaptor err*/
1890d59a3d2SAxel Dörfler #define SCSI_BUS_RESET_DENIED	0x1A	/* SCSI bus reset denied */
1900d59a3d2SAxel Dörfler 
1910d59a3d2SAxel Dörfler #define SCSI_IDE				0x33	/* Initiator Detected Error Received */
1920d59a3d2SAxel Dörfler #define SCSI_RESRC_UNAVAIL		0x34	/* Resource unavailable */
1930d59a3d2SAxel Dörfler #define SCSI_UNACKED_EVENT		0x35	/* Unacknowledged event by host */
1940d59a3d2SAxel Dörfler #define SCSI_LUN_INVALID		0x38	/* LUN supplied is invalid */
1950d59a3d2SAxel Dörfler #define SCSI_TID_INVALID		0x39	/* Target ID supplied is invalid */
1960d59a3d2SAxel Dörfler #define SCSI_FUNC_NOTAVAIL		0x3A	/* The requ. func is not available */
1970d59a3d2SAxel Dörfler #define SCSI_NO_NEXUS			0x3B	/* Nexus is not established */
1980d59a3d2SAxel Dörfler #define SCSI_IID_INVALID		0x3C	/* The initiator ID is invalid */
1990d59a3d2SAxel Dörfler #define SCSI_CDB_RECVD			0x3D	/* The SCSI CDB has been received */
2000d59a3d2SAxel Dörfler #define SCSI_LUN_ALLREADY_ENAB	0x3E	/* LUN already enabled */
2010d59a3d2SAxel Dörfler #define SCSI_SCSI_BUSY			0x3F	/* SCSI bus busy */
2020d59a3d2SAxel Dörfler 
2030d59a3d2SAxel Dörfler #define SCSI_AUTOSNS_VALID		0x80	/* Autosense data valid for target */
2040d59a3d2SAxel Dörfler 
2050d59a3d2SAxel Dörfler #define SCSI_SUBSYS_STATUS_MASK 0x3F	/* Mask bits for just the status # */
2060d59a3d2SAxel Dörfler 
2070d59a3d2SAxel Dörfler 
2080d59a3d2SAxel Dörfler // Defines for the flags field
2090d59a3d2SAxel Dörfler 
2100d59a3d2SAxel Dörfler #define SCSI_DIR_RESV			0x00000000	/* Data direction (00: reserved) */
2110d59a3d2SAxel Dörfler #define SCSI_DIR_IN				0x00000040	/* Data direction (01: DATA IN) */
2120d59a3d2SAxel Dörfler #define SCSI_DIR_OUT			0x00000080	/* Data direction (10: DATA OUT) */
2130d59a3d2SAxel Dörfler #define SCSI_DIR_NONE			0x000000C0	/* Data direction (11: no data) */
2140d59a3d2SAxel Dörfler #define SCSI_DIR_MASK			0x000000C0
2150d59a3d2SAxel Dörfler 
2160d59a3d2SAxel Dörfler #define SCSI_DIS_AUTOSENSE		0x00000020	/* Disable autosense feature */
2170d59a3d2SAxel Dörfler #define SCSI_ORDERED_QTAG		0x00000010	// ordered queue (cannot overtake/be overtaken)
2180d59a3d2SAxel Dörfler #define SCSI_DMA_SAFE			0x00000008	// set if data buffer is DMA approved
2190d59a3d2SAxel Dörfler 
2200d59a3d2SAxel Dörfler #define SCSI_DIS_DISCONNECT		0x00008000	/* Disable disconnect */
2210d59a3d2SAxel Dörfler #define SCSI_INITIATE_SYNC		0x00004000	/* Attempt Sync data xfer, and SDTR */
2220d59a3d2SAxel Dörfler #define SCSI_DIS_SYNC			0x00002000	/* Disable sync, go to async */
2230d59a3d2SAxel Dörfler #define SCSI_ENG_SYNC			0x00000200	/* Flush resid bytes before cmplt */
2240d59a3d2SAxel Dörfler 
2250d59a3d2SAxel Dörfler 
2260d59a3d2SAxel Dörfler // Defines for the Path Inquiry CCB fields
2270d59a3d2SAxel Dörfler 
2280d59a3d2SAxel Dörfler // flags in hba_inquiry
2290d59a3d2SAxel Dörfler #define SCSI_PI_MDP_ABLE		0x80	/* Supports MDP message */
2300d59a3d2SAxel Dörfler #define SCSI_PI_WIDE_32			0x40	/* Supports 32 bit wide SCSI */
2310d59a3d2SAxel Dörfler #define SCSI_PI_WIDE_16			0x20	/* Supports 16 bit wide SCSI */
2320d59a3d2SAxel Dörfler #define SCSI_PI_SDTR_ABLE		0x10	/* Supports SDTR message */
2330d59a3d2SAxel Dörfler #define SCSI_PI_TAG_ABLE		0x02	/* Supports tag queue message */
2340d59a3d2SAxel Dörfler #define SCSI_PI_SOFT_RST		0x01	/* Supports soft reset */
2350d59a3d2SAxel Dörfler 
2360d59a3d2SAxel Dörfler // flags in hba_misc
2370d59a3d2SAxel Dörfler #define SCSI_PIM_SCANHILO		0x80	/* Bus scans from ID 7 to ID 0 */
2380d59a3d2SAxel Dörfler #define SCSI_PIM_NOREMOVE		0x40	/* Removable dev not included in scan */
2390d59a3d2SAxel Dörfler 
2400d59a3d2SAxel Dörfler // sizes of inquiry fields
2410d59a3d2SAxel Dörfler #define SCSI_VUHBA		14				/* Vendor Unique HBA length */
2420d59a3d2SAxel Dörfler #define SCSI_SIM_ID		16				/* ASCII string len for SIM ID */
2430d59a3d2SAxel Dörfler #define SCSI_HBA_ID		16				/* ASCII string len for HBA ID */
2440d59a3d2SAxel Dörfler #define SCSI_FAM_ID		16				/* ASCII string len for FAMILY ID */
2450d59a3d2SAxel Dörfler #define SCSI_TYPE_ID	16				/* ASCII string len for TYPE ID */
2460d59a3d2SAxel Dörfler #define SCSI_VERS		 8				/* ASCII string len for SIM & HBA vers */
2470d59a3d2SAxel Dörfler 
2480d59a3d2SAxel Dörfler 
2490d59a3d2SAxel Dörfler // Path inquiry, extended by BeOS XPT_EXTENDED_PATH_INQ parameters
2506be1e37dSAxel Dörfler typedef struct {
2510d59a3d2SAxel Dörfler 	uchar		version_num;			/* Version number for the SIM/HBA */
2520d59a3d2SAxel Dörfler 	uchar		hba_inquiry;			/* Mimic of INQ byte 7 for the HBA */
2530d59a3d2SAxel Dörfler 	uchar		hba_misc;				/* Misc HBA feature flags */
2540d59a3d2SAxel Dörfler 	uchar		vuhba_flags[SCSI_VUHBA];/* Vendor unique capabilities */
2550d59a3d2SAxel Dörfler 	uchar		initiator_id;			/* ID of the HBA on the SCSI bus */
256786a38f5SJérôme Duval 	uint32		hba_queue_size;			// size of adapters command queue
2570d59a3d2SAxel Dörfler 	char		sim_vid[SCSI_SIM_ID];	/* Vendor ID of the SIM */
2580d59a3d2SAxel Dörfler 	char		hba_vid[SCSI_HBA_ID];	/* Vendor ID of the HBA */
2590d59a3d2SAxel Dörfler 
2600d59a3d2SAxel Dörfler 	char		sim_version[SCSI_VERS];	/* SIM version number */
2610d59a3d2SAxel Dörfler 	char		hba_version[SCSI_VERS];	/* HBA version number */
2620d59a3d2SAxel Dörfler 	char		controller_family[SCSI_FAM_ID]; /* Controller family */
2630d59a3d2SAxel Dörfler 	char		controller_type[SCSI_TYPE_ID]; /* Controller type */
2640d59a3d2SAxel Dörfler } scsi_path_inquiry;
2650d59a3d2SAxel Dörfler 
2660d59a3d2SAxel Dörfler 
2670d59a3d2SAxel Dörfler // Device node
2680d59a3d2SAxel Dörfler 
2690d59a3d2SAxel Dörfler // target (uint8)
2700d59a3d2SAxel Dörfler #define SCSI_DEVICE_TARGET_ID_ITEM "scsi/target_id"
2710d59a3d2SAxel Dörfler // lun (uint8)
2720d59a3d2SAxel Dörfler #define SCSI_DEVICE_TARGET_LUN_ITEM "scsi/target_lun"
2730d59a3d2SAxel Dörfler // node type
2740d59a3d2SAxel Dörfler #define SCSI_DEVICE_TYPE_NAME "scsi/device/v1"
2750d59a3d2SAxel Dörfler // device inquiry data (raw scsi_res_inquiry)
2760d59a3d2SAxel Dörfler #define SCSI_DEVICE_INQUIRY_ITEM "scsi/device_inquiry"
2770d59a3d2SAxel Dörfler // device type (uint8)
2780d59a3d2SAxel Dörfler #define SCSI_DEVICE_TYPE_ITEM "scsi/type"
2790d59a3d2SAxel Dörfler // vendor name (string)
2800d59a3d2SAxel Dörfler #define SCSI_DEVICE_VENDOR_ITEM "scsi/vendor"
2810d59a3d2SAxel Dörfler // product name (string)
2820d59a3d2SAxel Dörfler #define SCSI_DEVICE_PRODUCT_ITEM "scsi/product"
2830d59a3d2SAxel Dörfler // revision (string)
2840d59a3d2SAxel Dörfler #define SCSI_DEVICE_REVISION_ITEM "scsi/revision"
2850d59a3d2SAxel Dörfler 
286402a4a4eSMarcus Overhagen // maximum targets on scsi bus
287402a4a4eSMarcus Overhagen #define SCSI_DEVICE_MAX_TARGET_COUNT "scsi/max_target_count"
288a0f12421SJérôme Duval // maximum luns on scsi bus
289a0f12421SJérôme Duval #define SCSI_DEVICE_MAX_LUN_COUNT "scsi/max_lun_count"
290402a4a4eSMarcus Overhagen 
2910d59a3d2SAxel Dörfler // directory containing links to peripheral drivers
2920d59a3d2SAxel Dörfler #define SCSI_PERIPHERAL_DRIVERS_DIR "scsi"
2930d59a3d2SAxel Dörfler 
2940d59a3d2SAxel Dörfler // bus manager device interface for peripheral driver
2950d59a3d2SAxel Dörfler typedef struct scsi_device_interface {
296b83a8af4SAxel Dörfler 	driver_module_info info;
2970d59a3d2SAxel Dörfler 
2980d59a3d2SAxel Dörfler 	scsi_ccb *(*alloc_ccb)(scsi_device device);
2990d59a3d2SAxel Dörfler 	void (*free_ccb)(scsi_ccb *ccb);
3000d59a3d2SAxel Dörfler 
3010d59a3d2SAxel Dörfler 	// execute command asynchronously
302*77463640SAugustin Cavalier 	// when it's finished, the condvar of the ccb is released
3030d59a3d2SAxel Dörfler 	// you must provide a S/G list if data_len != 0
3040d59a3d2SAxel Dörfler 	void (*async_io)(scsi_ccb *ccb);
3050d59a3d2SAxel Dörfler 	// execute command synchronously
3060d59a3d2SAxel Dörfler 	// you don't need to provide a S/G list nor have to lock data
3070d59a3d2SAxel Dörfler 	void (*sync_io)(scsi_ccb *ccb);
3080d59a3d2SAxel Dörfler 
3090d59a3d2SAxel Dörfler 	// abort request
3100d59a3d2SAxel Dörfler 	uchar (*abort)(scsi_ccb *ccb_to_abort);
3110d59a3d2SAxel Dörfler 	// reset device
3120d59a3d2SAxel Dörfler 	uchar (*reset_device)(scsi_device device);
3130d59a3d2SAxel Dörfler 	// terminate request
3140d59a3d2SAxel Dörfler 	uchar (*term_io)(scsi_ccb *ccb_to_terminate);
315c9fc73fcSAxel Dörfler 
316c9fc73fcSAxel Dörfler 	status_t (*ioctl)(scsi_device device, uint32 op, void *buffer, size_t length);
3170d59a3d2SAxel Dörfler } scsi_device_interface;
3180d59a3d2SAxel Dörfler 
319368167edSAxel Dörfler #define SCSI_DEVICE_MODULE_NAME "bus_managers/scsi/device/driver_v1"
3200d59a3d2SAxel Dörfler 
3210d59a3d2SAxel Dörfler 
3220d59a3d2SAxel Dörfler // Bus node
3230d59a3d2SAxel Dörfler 
3240d59a3d2SAxel Dörfler // attributes:
3250d59a3d2SAxel Dörfler 
3260d59a3d2SAxel Dörfler // path (uint8)
3270d59a3d2SAxel Dörfler #define SCSI_BUS_PATH_ID_ITEM "scsi/path_id"
3280d59a3d2SAxel Dörfler // node type
3290d59a3d2SAxel Dörfler #define SCSI_BUS_TYPE_NAME "scsi/bus"
3300d59a3d2SAxel Dörfler 
3310d59a3d2SAxel Dörfler // SCSI bus node driver.
3320d59a3d2SAxel Dörfler // This interface can be used by peripheral drivers to access the
3330d59a3d2SAxel Dörfler // bus directly.
3340d59a3d2SAxel Dörfler typedef struct scsi_bus_interface {
335368167edSAxel Dörfler 	driver_module_info info;
3360d59a3d2SAxel Dörfler 
3370d59a3d2SAxel Dörfler 	// get information about host controller
3380d59a3d2SAxel Dörfler 	uchar (*path_inquiry)(scsi_bus bus, scsi_path_inquiry *inquiry_data);
3390d59a3d2SAxel Dörfler 	// reset SCSI bus
3400d59a3d2SAxel Dörfler 	uchar (*reset_bus)(scsi_bus bus);
3410d59a3d2SAxel Dörfler } scsi_bus_interface;
3420d59a3d2SAxel Dörfler 
3430d59a3d2SAxel Dörfler // name of SCSI bus node driver
344368167edSAxel Dörfler #define SCSI_BUS_MODULE_NAME "bus_managers/scsi/bus/driver_v1"
3450d59a3d2SAxel Dörfler 
3460d59a3d2SAxel Dörfler 
3470d59a3d2SAxel Dörfler // Interface for SIM
3480d59a3d2SAxel Dörfler 
3490d59a3d2SAxel Dörfler // cookie for dpc
3500d59a3d2SAxel Dörfler typedef struct scsi_dpc_info *scsi_dpc_cookie;
3510d59a3d2SAxel Dörfler 
3520d59a3d2SAxel Dörfler // Bus manager interface used by SCSI controller drivers.
3530d59a3d2SAxel Dörfler // SCSI controller drivers get this interface passed via their init_device
3540d59a3d2SAxel Dörfler // method. Further, they must specify this driver as their fixed consumer.
3550d59a3d2SAxel Dörfler typedef struct scsi_for_sim_interface {
356b83a8af4SAxel Dörfler 	driver_module_info info;
3570d59a3d2SAxel Dörfler 
3580d59a3d2SAxel Dörfler 	// put request into wait queue because of overflow
3590d59a3d2SAxel Dörfler 	// bus_overflow: true - too many bus requests
3600d59a3d2SAxel Dörfler 	//               false - too many device requests
3610d59a3d2SAxel Dörfler 	// bus/device won't receive requests until cont_sent_bus/cont_send_device
3620d59a3d2SAxel Dörfler 	// is called or a request is finished via finished();
3630d59a3d2SAxel Dörfler 	// to avoid race conditions (reporting a full and a available bus at once)
3640d59a3d2SAxel Dörfler 	// the SIM should synchronize calls to requeue, resubmit and finished
3650d59a3d2SAxel Dörfler 	void (*requeue)(scsi_ccb *ccb, bool bus_overflow);
3660d59a3d2SAxel Dörfler 	// resubmit request ASAP
3670d59a3d2SAxel Dörfler 	// to be used if execution of request went wrong and must be retried
3680d59a3d2SAxel Dörfler 	void (*resubmit)(scsi_ccb *ccb);
3690d59a3d2SAxel Dörfler 	// mark request as being finished
3700d59a3d2SAxel Dörfler 	// num_requests: number of requests that were handled by device
3710d59a3d2SAxel Dörfler 	//               when the request was sent (read: how full was the device
3720d59a3d2SAxel Dörfler 	//               queue); needed to find out how large the device queue is;
3730d59a3d2SAxel Dörfler 	//               e.g. if three were already running plus this request makes
3740d59a3d2SAxel Dörfler 	//               num_requests=4
3750d59a3d2SAxel Dörfler 	void (*finished)(scsi_ccb *ccb, uint num_requests);
3760d59a3d2SAxel Dörfler 
3770d59a3d2SAxel Dörfler 	// following functions return error on invalid arguments only
3780d59a3d2SAxel Dörfler 	status_t (*alloc_dpc)(scsi_dpc_cookie *dpc);
3790d59a3d2SAxel Dörfler 	status_t (*free_dpc)(scsi_dpc_cookie dpc);
3800d59a3d2SAxel Dörfler 	status_t (*schedule_dpc)(scsi_bus cookie, scsi_dpc_cookie dpc, /*int flags,*/
3810d59a3d2SAxel Dörfler 		void (*func)( void * ), void *arg);
3820d59a3d2SAxel Dörfler 
3830d59a3d2SAxel Dörfler 	// block entire bus (can be nested)
3840d59a3d2SAxel Dörfler 	// no more request will be submitted to this bus
3850d59a3d2SAxel Dörfler 	void (*block_bus)(scsi_bus bus);
3860d59a3d2SAxel Dörfler 	// unblock entire bus
3870d59a3d2SAxel Dörfler 	// requests will be submitted to bus ASAP
3880d59a3d2SAxel Dörfler 	void (*unblock_bus)(scsi_bus bus);
3890d59a3d2SAxel Dörfler 	// block one device
3900d59a3d2SAxel Dörfler 	// no more requests will be submitted to this device
3910d59a3d2SAxel Dörfler 	void (*block_device)(scsi_device device);
3920d59a3d2SAxel Dörfler 	// unblock device
3930d59a3d2SAxel Dörfler 	// requests for this device will be submitted ASAP
3940d59a3d2SAxel Dörfler 	void (*unblock_device)(scsi_device device);
3950d59a3d2SAxel Dörfler 
3960d59a3d2SAxel Dörfler 	// terminate bus overflow condition (see "requeue")
3970d59a3d2SAxel Dörfler 	void (*cont_send_bus)(scsi_bus bus);
3980d59a3d2SAxel Dörfler 	// terminate device overflow condition (see "requeue")
3990d59a3d2SAxel Dörfler 	void (*cont_send_device)(scsi_device device);
4000d59a3d2SAxel Dörfler } scsi_for_sim_interface;
4010d59a3d2SAxel Dörfler 
4020d59a3d2SAxel Dörfler 
403368167edSAxel Dörfler #define SCSI_FOR_SIM_MODULE_NAME "bus_managers/scsi/sim/driver_v1"
4040d59a3d2SAxel Dörfler 
4050d59a3d2SAxel Dörfler 
4060d59a3d2SAxel Dörfler // SIM Node
4070d59a3d2SAxel Dörfler 
4080d59a3d2SAxel Dörfler // attributes:
4090d59a3d2SAxel Dörfler 
4100d59a3d2SAxel Dörfler // node type
4110d59a3d2SAxel Dörfler #define SCSI_SIM_TYPE_NAME "bus/scsi/v1"
4120d59a3d2SAxel Dörfler // controller name (required, string)
4130d59a3d2SAxel Dörfler #define SCSI_DESCRIPTION_CONTROLLER_NAME "controller_name"
4140d59a3d2SAxel Dörfler 
415c42a837eSMarcus Overhagen typedef void *scsi_sim_cookie;
4160d59a3d2SAxel Dörfler 
4170d59a3d2SAxel Dörfler // SIM interface
4180d59a3d2SAxel Dörfler // SCSI controller drivers must provide this interface
4190d59a3d2SAxel Dörfler typedef struct scsi_sim_interface {
420b83a8af4SAxel Dörfler 	driver_module_info info;
4210d59a3d2SAxel Dörfler 
422368167edSAxel Dörfler 	void (*set_scsi_bus)(scsi_sim_cookie cookie, scsi_bus bus);
423368167edSAxel Dörfler 
4240d59a3d2SAxel Dörfler 	// execute request
4250d59a3d2SAxel Dörfler 	void (*scsi_io)(scsi_sim_cookie cookie, scsi_ccb *ccb);
4260d59a3d2SAxel Dörfler 	// abort request
4270d59a3d2SAxel Dörfler 	uchar (*abort)(scsi_sim_cookie cookie, scsi_ccb *ccb_to_abort);
4280d59a3d2SAxel Dörfler 	// reset device
4290d59a3d2SAxel Dörfler 	uchar (*reset_device)(scsi_sim_cookie cookie, uchar target_id, uchar target_lun);
4300d59a3d2SAxel Dörfler 	// terminate request
4310d59a3d2SAxel Dörfler 	uchar (*term_io)(scsi_sim_cookie cookie, scsi_ccb *ccb_to_terminate);
4320d59a3d2SAxel Dörfler 
4330d59a3d2SAxel Dörfler 	// get information about bus
4340d59a3d2SAxel Dörfler 	uchar (*path_inquiry)(scsi_sim_cookie cookie, scsi_path_inquiry *inquiry_data);
4350d59a3d2SAxel Dörfler 	// scan bus
4360d59a3d2SAxel Dörfler 	// this is called immediately before the SCSI bus manager scans the bus
4370d59a3d2SAxel Dörfler 	uchar (*scan_bus)(scsi_sim_cookie cookie);
4380d59a3d2SAxel Dörfler 	// reset bus
4390d59a3d2SAxel Dörfler 	uchar (*reset_bus)(scsi_sim_cookie cookie);
4400d59a3d2SAxel Dörfler 
4410d59a3d2SAxel Dörfler 	// get restrictions of one device
4420d59a3d2SAxel Dörfler 	// (used for non-SCSI transport protocols and bug fixes)
443368167edSAxel Dörfler 	void (*get_restrictions)(scsi_sim_cookie 	cookie,
4440d59a3d2SAxel Dörfler 		uchar				target_id,		// target id
4450d59a3d2SAxel Dörfler 		bool				*is_atapi, 		// set to true if this is an ATAPI device that
4460d59a3d2SAxel Dörfler 											// needs some commands emulated
4470d59a3d2SAxel Dörfler 		bool				*no_autosense,	// set to true if there is no autosense;
4480d59a3d2SAxel Dörfler 											// the SCSI bus manager will request sense on
449f0d174e9SMarcus Overhagen 											// SCSI_REQ_CMP_ERR/SCSI_STATUS_CHECK_CONDITION
4500d59a3d2SAxel Dörfler 		uint32 				*max_blocks );	// maximum number of blocks per transfer if > 0;
4510d59a3d2SAxel Dörfler 											// used for buggy devices that cannot handle
4520d59a3d2SAxel Dörfler 											// large transfers (read: ATAPI ZIP drives)
453c9fc73fcSAxel Dörfler 
454c9fc73fcSAxel Dörfler 	status_t (*ioctl)(scsi_sim_cookie, uint8 targetID, uint32 op, void *buffer, size_t length);
4550d59a3d2SAxel Dörfler } scsi_sim_interface;
4560d59a3d2SAxel Dörfler 
4570d59a3d2SAxel Dörfler 
4586be1e37dSAxel Dörfler #endif	/* _SCSI_BUSMANAGER_H */
459