Training courses

Kernel and Embedded Linux

Bootlin training courses

Embedded Linux, kernel,
Yocto Project, Buildroot, real-time,
graphics, boot time, debugging...

Bootlin logo

Elixir Cross Referencer

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
/*	$NetBSD: scsipiconf.h,v 1.130 2019/03/28 10:44:29 kardel Exp $	*/

/*-
 * Copyright (c) 1998, 1999, 2000, 2004 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Charles M. Hannum; by Jason R. Thorpe of the Numerical Aerospace
 * Simulation Facility, NASA Ames Research Center.
 *
 * 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, 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
 */

/*
 * Originally written by Julian Elischer (julian@tfs.com)
 * for TRW Financial Systems for use under the MACH(2.5) operating system.
 *
 * TRW Financial Systems, in accordance with their agreement with Carnegie
 * Mellon University, makes this software available to CMU to distribute
 * or use in any manner that they see fit as long as this message is kept with
 * the software. For this reason TFS also grants any other persons or
 * organisations permission to use or modify this software.
 *
 * TFS supplies this software to be publicly redistributed
 * on the understanding that TFS is not responsible for the correct
 * functioning of this software in any circumstances.
 *
 * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
 */

#ifndef _DEV_SCSIPI_SCSIPICONF_H_
#define _DEV_SCSIPI_SCSIPICONF_H_

typedef	int	boolean;

#include <sys/callout.h>
#include <sys/queue.h>
#include <sys/condvar.h>
#include <dev/scsipi/scsi_spc.h>
#include <dev/scsipi/scsipi_debug.h>

struct buf;
struct proc;
struct device;
struct scsipi_channel;
struct scsipi_periph;
struct scsipi_xfer;

/*
 * The following defines the scsipi_xfer queue.
 */
TAILQ_HEAD(scsipi_xfer_queue, scsipi_xfer);

struct scsipi_generic {
	u_int8_t opcode;
	u_int8_t bytes[15];
};


/*
 * scsipi_async_event_t:
 *
 *	Asynchronous events from the adapter to the mid-layer and
 *	peripheral.
 *
 *	Arguments:
 *
 *	ASYNC_EVENT_MAX_OPENINGS	scsipi_max_openings * -- max
 *					openings, device specified in
 *					parameters
 *
 *	ASYNC_EVENT_XFER_MODE		scsipi_xfer_mode * -- xfer mode
 *					parameters changed for I_T Nexus
 *	ASYNC_EVENT_RESET		NULL - channel has been reset
 */
typedef enum {
	ASYNC_EVENT_MAX_OPENINGS,	/* set max openings on periph */
	ASYNC_EVENT_XFER_MODE,		/* xfer mode update for I_T */
	ASYNC_EVENT_RESET		/* channel reset */
} scsipi_async_event_t;

/*
 * scsipi_max_openings:
 *
 *	Argument for an ASYNC_EVENT_MAX_OPENINGS event.
 */
struct scsipi_max_openings {
	int	mo_target;		/* openings are for this target... */
	int	mo_lun;			/* ...and this lun */
	int	mo_openings;		/* openings value */
};

/*
 * scsipi_xfer_mode:
 *
 *	Argument for an ASYNC_EVENT_XFER_MODE event.
 */
struct scsipi_xfer_mode {
	int	xm_target;		/* target, for I_T Nexus */
	int	xm_mode;		/* PERIPH_CAP* bits */
	int	xm_period;		/* sync period */
	int	xm_offset;		/* sync offset */
};


/*
 * scsipi_adapter_req_t:
 *
 *	Requests that can be made of an adapter.
 *
 *	Arguments:
 *
 *	ADAPTER_REQ_RUN_XFER		scsipi_xfer * -- the xfer which
 *					is to be run
 *
 *	ADAPTER_REQ_GROW_RESOURCES	no argument
 *
 *	ADAPTER_REQ_SET_XFER_MODE	scsipi_xfer_mode * -- set the xfer
 *					mode for the I_T Nexus according to
 *					this
 */
typedef enum {
	ADAPTER_REQ_RUN_XFER,		/* run a scsipi_xfer */
	ADAPTER_REQ_GROW_RESOURCES,	/* grow xfer execution resources */
	ADAPTER_REQ_SET_XFER_MODE	/* set xfer mode */
} scsipi_adapter_req_t;

#ifdef _KERNEL
/*
 * scsipi_periphsw:
 *
 *	Callbacks into periph driver from midlayer.
 *
 *	psw_error	Called by the bustype's interpret-sense routine
 *			to do periph-specific sense handling.
 *
 *	psw_start	Called by midlayer to restart a device once
 *			more command openings become available.
 *
 *	psw_async	Called by midlayer when an asynchronous event
 *			from the adapter occurs.
 *
 *	psw_done	Called by the midlayer when an xfer has completed.
 */
struct scsipi_periphsw {
	int	(*psw_error)(struct scsipi_xfer *);
	void	(*psw_start)(struct scsipi_periph *);
	int	(*psw_async)(struct scsipi_periph *,
		    scsipi_async_event_t, void *);
	void	(*psw_done)(struct scsipi_xfer *, int);
};

struct disk_parms;
struct scsipi_inquiry_pattern;

/*
 * scsipi_adapter:
 *
 *	This structure describes an instance of a SCSIPI adapter.
 *
 *	Note that `adapt_openings' is used by (the common case of) adapters
 *	which have per-adapter resources.  If an adapter's command resources
 *	are associated with a channel, then the `chan_openings' below will
 *	be used instead.
 *
 *	Note that all adapter entry points take a pointer to a channel,
 *	as an adapter may have more than one channel, and the channel
 *	structure contains the channel number.
 */
struct scsipi_adapter {
	device_t adapt_dev;	/* pointer to adapter's device */
	int	adapt_nchannels;	/* number of adapter channels */
	volatile int	adapt_refcnt;		/* adapter's reference count */
	int	adapt_openings;		/* total # of command openings */
	int	adapt_max_periph;	/* max openings per periph */
	int	adapt_flags;

	void	(*adapt_request)(struct scsipi_channel *,
		    scsipi_adapter_req_t, void *);
	void	(*adapt_minphys)(struct buf *);
	int	(*adapt_ioctl)(struct scsipi_channel *, u_long,
		    void *, int, struct proc *);
	int	(*adapt_enable)(device_t, int);
	int	(*adapt_getgeom)(struct scsipi_periph *,
			struct disk_parms *, u_long);
	int	(*adapt_accesschk)(struct scsipi_periph *,
			struct scsipi_inquiry_pattern *);

	kmutex_t adapt_mtx;
	volatile int	adapt_running;	/* how many users of mutex */
};

/* adapt_flags */
#define SCSIPI_ADAPT_POLL_ONLY	0x01 /* Adaptor can't do interrupts. */
#define SCSIPI_ADAPT_MPSAFE     0x02 /* Adaptor doesn't need kernel lock */

void scsipi_adapter_minphys(struct scsipi_channel *, struct buf *);
void scsipi_adapter_request(struct scsipi_channel *,
	scsipi_adapter_req_t, void *);
int scsipi_adapter_ioctl(struct scsipi_channel *, u_long,
	void *, int, struct proc *);
int scsipi_adapter_enable(struct scsipi_adapter *, int);
#endif


/*
 * scsipi_bustype:
 *
 *	This structure describes a SCSIPI bus type.
 *	The bustype_type member is shared with struct ata_bustype
 *	(because we can ata, atapi or scsi busses to the same controller)
 */
struct scsipi_bustype {
	int	bustype_type;		/* symbolic name of type */

	void	(*bustype_cmd)(struct scsipi_xfer *);
	int	(*bustype_interpret_sense)(struct scsipi_xfer *);
	void	(*bustype_printaddr)(struct scsipi_periph *);
	void	(*bustype_kill_pending)(struct scsipi_periph *);
	void	(*bustype_async_event_xfer_mode)(struct scsipi_channel *,
		    void *);
};

/* bustype_type */
/* type is stored in the first byte */
#define SCSIPI_BUSTYPE_TYPE_SHIFT 0
#define SCSIPI_BUSTYPE_TYPE(x) (((x) >> SCSIPI_BUSTYPE_TYPE_SHIFT) & 0xff)
#define	SCSIPI_BUSTYPE_SCSI	0 /* parallel SCSI */
#define	SCSIPI_BUSTYPE_ATAPI	1
/* #define SCSIPI_BUSTYPE_ATA	2 */
/* subtype is stored in the second byte */
#define SCSIPI_BUSTYPE_SUBTYPE_SHIFT 8
#define SCSIPI_BUSTYPE_SUBTYPE(x) (((x) >> SCSIPI_BUSTYPE_SUBTYPE_SHIFT) & 0xff)

#define SCSIPI_BUSTYPE_BUSTYPE(t, s) \
    ((t) << SCSIPI_BUSTYPE_TYPE_SHIFT | (s) << SCSIPI_BUSTYPE_SUBTYPE_SHIFT)
/* subtypes are defined in each bus type headers */

/*
 * scsipi_channel:
 *
 *	This structure describes a single channel of a SCSIPI adapter.
 *	An adapter may have one or more channels.  See the comment above
 *	regarding the resource counter.
 *	Note: chan_bustype has to be first member, as its bustype_type member
 * 	is shared with the aa_bustype member of struct ata_atapi_attach.
 */

#define	SCSIPI_CHAN_PERIPH_BUCKETS	16
#define	SCSIPI_CHAN_PERIPH_HASHMASK	(SCSIPI_CHAN_PERIPH_BUCKETS - 1)

#ifdef _KERNEL
struct scsipi_channel {
	const struct scsipi_bustype *chan_bustype; /* channel's bus type */
	const char *chan_name;	/* this channel's name */

	struct scsipi_adapter *chan_adapter; /* pointer to our adapter */

	/* Periphs for this channel. */
	LIST_HEAD(, scsipi_periph) chan_periphtab[SCSIPI_CHAN_PERIPH_BUCKETS];

	int	chan_channel;		/* channel number */
	int	chan_flags;		/* channel flags */
	int	chan_openings;		/* number of command openings */
	int	chan_max_periph;	/* max openings per periph */

	int	chan_ntargets;		/* number of targets */
	int	chan_nluns;		/* number of luns */
	int	chan_id;		/* adapter's ID for this channel */

	int	chan_defquirks;		/* default device's quirks */

	struct lwp *chan_dthread;	/* discovery thread */
	struct lwp *chan_thread;	/* completion thread */
	int	chan_tflags;		/* flags for the completion thread */

	int	chan_qfreeze;		/* freeze count for queue */

	/* Job queue for this channel. */
	struct scsipi_xfer_queue chan_queue;

	/* Completed (async) jobs. */
	struct scsipi_xfer_queue chan_complete;

	/* callback we may have to call from completion thread */
	void (*chan_callback)(struct scsipi_channel *, void *);
	void *chan_callback_arg;

	/* callback we may have to call after forking the kthread */
	void (*chan_init_cb)(struct scsipi_channel *, void *);
	void *chan_init_cb_arg;

	kcondvar_t chan_cv_comp;
	kcondvar_t chan_cv_thr;
	kcondvar_t chan_cv_xs;

#define chan_cv_complete(ch) (&(ch)->chan_cv_comp)
#define chan_cv_thread(ch) (&(ch)->chan_cv_thr)
};

#define chan_running(ch) ((ch)->chan_adapter->adapt_running)
#define chan_mtx(ch) (&(ch)->chan_adapter->adapt_mtx)
#endif

/* chan_flags */
#define	SCSIPI_CHAN_OPENINGS	0x01	/* use chan_openings */
#define	SCSIPI_CHAN_CANGROW	0x02	/* channel can grow resources */
#define	SCSIPI_CHAN_NOSETTLE	0x04	/* don't wait for devices to settle */
#define	SCSIPI_CHAN_TACTIVE	0x08	/* completion thread is active */

/* chan thread flags (chan_tflags) */
#define	SCSIPI_CHANT_SHUTDOWN	0x01	/* channel is shutting down */
#define	SCSIPI_CHANT_CALLBACK	0x02	/* has to call chan_callback() */
#define	SCSIPI_CHANT_KICK	0x04	/* need to run queues */
#define	SCSIPI_CHANT_GROWRES	0x08	/* call ADAPTER_REQ_GROW_RESOURCES */

#define	SCSIPI_CHAN_MAX_PERIPH(chan)					\
	(((chan)->chan_flags & SCSIPI_CHAN_OPENINGS) ?			\
	 (chan)->chan_max_periph : (chan)->chan_adapter->adapt_max_periph)


#define	scsipi_printaddr(periph)					\
	(*(periph)->periph_channel->chan_bustype->bustype_printaddr)((periph))

#define	scsipi_periph_bustype(periph)					\
	(periph)->periph_channel->chan_bustype->bustype_type


/*
 * Number of tag words in a periph structure:
 *
 *	n_tag_words = ((256 / NBBY) / sizeof(u_int32_t))
 */
#define	PERIPH_NTAGWORDS	((256 / 8) / sizeof(u_int32_t))

#ifdef _KERNEL
/*
 * scsipi_opcodes:
 *      This optionally allocated structure documents
 *      valid opcodes and timeout values for the respective
 *      opcodes overriding the requested timeouts.
 *      It is created when SCSI_MAINTENANCE_IN/
 *      RSOC_REPORT_SUPPORTED_OPCODES can provide information
 *      at attach time.
 */
struct scsipi_opcodes 
{
	struct scsipi_opinfo
	{
		long          ti_timeout;	/* timeout in seconds (> 0 => VALID) */
		unsigned long ti_flags;
#define SCSIPI_TI_VALID  0x0001	        /* valid op code */
#define SCSIPI_TI_LOGGED 0x8000	        /* override logged during debug */
	} opcode_info[0x100];
};

/*
 * scsipi_periph:
 *
 *	This structure describes the path between a peripheral device
 *	and an adapter.  It contains a pointer to the adapter channel
 *	which in turn contains a pointer to the adapter.
 *
 * XXX Given the way NetBSD's autoconfiguration works, this is ...
 * XXX nasty.
 *
 *	Well, it's a lot nicer than it used to be, but there could
 *	still be an improvement.
 */
struct scsipi_periph {
	device_t periph_dev;	/* pointer to peripheral's device */
	struct scsipi_channel *periph_channel; /* channel we're connected to */

					/* link in channel's table of periphs */
	LIST_ENTRY(scsipi_periph) periph_hash;

	const struct scsipi_periphsw *periph_switch; /* peripheral's entry
							points */
	int	periph_openings;	/* max # of outstanding commands */
	int	periph_active;		/* current # of outstanding commands */
	int	periph_sent;		/* current # of commands sent to adapt*/

	int	periph_mode;		/* operation modes, CAP bits */
	int	periph_period;		/* sync period (factor) */
	int	periph_offset;		/* sync offset */

	/*
	 * Information gleaned from the inquiry data.
	 */
	u_int8_t periph_type;		/* basic device type */
	int	periph_cap;		/* capabilities */
	int	periph_quirks;		/* device's quirks */

	int	periph_flags;		/* misc. flags */
	int	periph_dbflags;		/* debugging flags */

	int	periph_target;		/* target ID (drive # on ATAPI) */
	int	periph_lun;		/* LUN (not used on ATAPI) */

	int	periph_version;		/* ANSI SCSI version */

	int	periph_qfreeze;		/* queue freeze count */

	/* available opcodes and timeout information */
	struct scsipi_opcodes *periph_opcs;
	
	/* Bitmap of free command tags. */
	u_int32_t periph_freetags[PERIPH_NTAGWORDS];

	/* Pending scsipi_xfers on this peripheral. */
	struct scsipi_xfer_queue periph_xferq;

	callout_t periph_callout;

	/* xfer which has a pending CHECK_CONDITION */
	struct scsipi_xfer *periph_xscheck;

	kcondvar_t periph_cv;
#define periph_cv_periph(p) (&(p)->periph_cv)
#define periph_cv_active(p) (&(p)->periph_cv)
};
#endif

/*
 * Macro to return the current xfer mode of a periph.
 */
#define	PERIPH_XFER_MODE(periph)					\
	(((periph)->periph_flags & PERIPH_MODE_VALID) ?			\
	 (periph)->periph_mode : 0)

/* periph_cap */
#define	PERIPH_CAP_ANEC		0x0001	/* async event notification */
#define	PERIPH_CAP_TERMIOP	0x0002	/* terminate i/o proc. messages */
#define	PERIPH_CAP_RELADR	0x0004	/* relative addressing */
#define	PERIPH_CAP_WIDE32	0x0008	/* wide-32 transfers */
#define	PERIPH_CAP_WIDE16	0x0010	/* wide-16 transfers */
		/*	XXX	0x0020	   reserved for ATAPI_CFG_DRQ_MASK */
		/*	XXX	0x0040	   reserved for ATAPI_CFG_DRQ_MASK */
#define	PERIPH_CAP_SYNC		0x0080	/* synchronous transfers */
#define	PERIPH_CAP_LINKCMDS	0x0100	/* linked commands */
#define	PERIPH_CAP_TQING	0x0200	/* tagged queueing */
#define	PERIPH_CAP_SFTRESET	0x0400	/* soft RESET condition response */
#define	PERIPH_CAP_CMD16	0x0800	/* 16 byte commands (ATAPI) */
#define	PERIPH_CAP_DT		0x1000	/* supports DT clock */
#define	PERIPH_CAP_QAS		0x2000	/* supports quick arbit. and select. */
#define	PERIPH_CAP_IUS		0x4000	/* supports information unit xfers */

/* periph_flags */
#define	PERIPH_REMOVABLE	0x0001	/* media is removable */
#define	PERIPH_MEDIA_LOADED	0x0002	/* media is loaded */
#define	PERIPH_WAITING		0x0004	/* process waiting for opening */
#define	PERIPH_OPEN		0x0008	/* device is open */
#define	PERIPH_WAITDRAIN	0x0010	/* waiting for pending xfers to drain */
#define	PERIPH_GROW_OPENINGS	0x0020	/* allow openings to grow */
#define	PERIPH_MODE_VALID	0x0040	/* periph_mode is valid */
#define	PERIPH_RECOVERING	0x0080	/* periph is recovering */
#define	PERIPH_RECOVERY_ACTIVE	0x0100	/* a recovery command is active */
#define PERIPH_KEEP_LABEL	0x0200	/* retain label after 'full' close */
#define	PERIPH_SENSE		0x0400	/* periph has sense pending */
#define PERIPH_UNTAG		0x0800	/* untagged command running */

/* periph_quirks */
#define	PQUIRK_AUTOSAVE		0x00000001	/* do implicit SAVE POINTERS */
#define	PQUIRK_NOSYNC		0x00000002	/* does not grok SDTR */
#define	PQUIRK_NOWIDE		0x00000004	/* does not grok WDTR */
#define	PQUIRK_NOTAG		0x00000008	/* does not grok tagged cmds */
#define	PQUIRK_NOLUNS		0x00000010	/* DTWT with LUNs */
#define	PQUIRK_FORCELUNS	0x00000020	/* prehistoric device groks
						   LUNs */
#define	PQUIRK_NOMODESENSE	0x00000040	/* device doesn't do MODE SENSE
						   properly */
#define	PQUIRK_NOSYNCCACHE	0x00000100	/* do not issue SYNC CACHE */
#define	PQUIRK_LITTLETOC	0x00000400	/* audio TOC is little-endian */
#define	PQUIRK_NOCAPACITY	0x00000800	/* no READ CD CAPACITY */
#define	PQUIRK_NOTUR		0x00001000	/* no TEST UNIT READY */
#define	PQUIRK_NODOORLOCK	0x00002000	/* can't lock door */
#define	PQUIRK_NOSENSE		0x00004000	/* can't REQUEST SENSE */
#define PQUIRK_ONLYBIG		0x00008000	/* only use SCSI_{R,W}_BIG */
#define PQUIRK_NOBIGMODESENSE	0x00040000	/* has no big mode-sense op */
#define PQUIRK_CAP_SYNC		0x00080000	/* SCSI device with ST sync op*/
#define PQUIRK_CAP_WIDE16	0x00100000	/* SCSI device with ST wide op*/
#define PQUIRK_CAP_NODT		0x00200000	/* signals DT, but can't. */
#define PQUIRK_START		0x00400000	/* needs start before tur */
#define	PQUIRK_NOFUA		0x00800000	/* does not grok FUA */
#define PQUIRK_NOREPSUPPOPC     0x01000000      /* does not grok
						   REPORT SUPPORTED OPCODES
						   to fetch device timeouts */
/*
 * Error values an adapter driver may return
 */
typedef enum {
	XS_NOERROR,		/* there is no error, (sense is invalid)  */
	XS_SENSE,		/* Check the returned sense for the error */
	XS_SHORTSENSE,		/* Check the ATAPI sense for the error	  */
	XS_DRIVER_STUFFUP,	/* Driver failed to perform operation     */
	XS_RESOURCE_SHORTAGE,	/* adapter resource shortage		  */
	XS_SELTIMEOUT,		/* The device timed out.. turned off?     */
	XS_TIMEOUT,		/* The Timeout reported was caught by SW  */
	XS_BUSY,		/* The device busy, try again later?      */
	XS_RESET,		/* bus was reset; possible retry command  */
	XS_REQUEUE		/* requeue this command */
} scsipi_xfer_result_t;

#ifdef _KERNEL
/*
 * Each scsipi transaction is fully described by one of these structures
 * It includes information about the source of the command and also the
 * device and adapter for which the command is destined.
 *
 * Before the HBA is given this transaction, channel_q is the linkage on
 * the related channel's chan_queue.
 *
 * When the this transaction is taken off the channel's chan_queue and
 * the HBA's request entry point is called with this transaction, the
 * HBA can use the channel_q tag for whatever it likes until it calls
 * scsipi_done for this transaction, at which time it has to stop
 * using channel_q.
 *
 * After scsipi_done is called with this transaction and if there was an
 * error on it, channel_q then becomes the linkage on the related channel's
 * chan_complete cqueue.
 *
 * The device_q member is maintained by the scsipi middle layer.  When
 * a device issues a command, the xfer is placed on that device's
 * pending commands queue.  When an xfer is done and freed, it is taken
 * off the device's queue.  This allows for a device to wait for all of
 * its pending commands to complete.
 */
struct scsipi_xfer {
	TAILQ_ENTRY(scsipi_xfer) channel_q; /* entry on channel queue */
	TAILQ_ENTRY(scsipi_xfer) device_q;  /* device's pending xfers */
	callout_t xs_callout;		/* callout for adapter use */
	int	xs_control;		/* control flags */
	volatile int xs_status;		/* status flags */
	struct scsipi_periph *xs_periph;/* peripheral doing the xfer */
	int	xs_retries;		/* the number of times to retry */
	int	xs_requeuecnt;		/* number of requeues */
	int	timeout;		/* in milliseconds */
	struct	scsipi_generic *cmd;	/* The scsipi command to execute */
	int	cmdlen;			/* how long it is */
	u_char	*data;			/* DMA address OR a uio address */
	int	datalen;		/* data len (blank if uio) */
	int	resid;			/* how much buffer was not touched */
	scsipi_xfer_result_t error;	/* an error value */
	struct	buf *bp;		/* If we need to associate with */
					/* a buf */
	union {
		struct  scsi_sense_data scsi_sense; /* 32 bytes */
		u_int32_t atapi_sense;
	} sense;

	struct scsipi_xfer *xs_sensefor;/* we are requesting sense for this */
					/* xfer */

	u_int8_t status;		/* SCSI status */

	/*
	 * Info for tagged command queueing.  This may or may not
	 * be used by a given adapter driver.  These are the same
	 * as the bytes in the tag message.
	 */
	u_int8_t xs_tag_type;		/* tag type */
	u_int8_t xs_tag_id;		/* tag ID */

	struct	scsipi_generic cmdstore
	    __aligned(4);		/* stash the command in here */

#define xs_cv(xs) (&(xs)->xs_periph->periph_channel->chan_cv_xs)
};
#endif

/*
 * scsipi_xfer control flags
 *
 * To do:
 *
 *	- figure out what to do with XS_CTL_ESCAPE
 *
 *	- replace XS_CTL_URGENT with an `xs_priority' field?
 */
#define	XS_CTL_NOSLEEP		0x00000001	/* don't sleep */
#define	XS_CTL_POLL		0x00000002	/* poll for completion */
#define	XS_CTL_DISCOVERY	0x00000004	/* doing device discovery */
#define	XS_CTL_ASYNC		0x00000008	/* command completes
						   asynchronously */
#define	XS_CTL_USERCMD		0x00000010	/* user issued command */
#define	XS_CTL_SILENT		0x00000020	/* don't print sense info */
#define	XS_CTL_IGNORE_NOT_READY	0x00000040	/* ignore NOT READY */
#define	XS_CTL_IGNORE_MEDIA_CHANGE 					\
				0x00000080	/* ignore media change */
#define	XS_CTL_IGNORE_ILLEGAL_REQUEST					\
				0x00000100	/* ignore ILLEGAL REQUEST */
#define	XS_CTL_SILENT_NODEV	0x00000200	/* don't print sense info
						   if sense info is nodev */
#define	XS_CTL_RESET		0x00000400	/* reset the device */
#define	XS_CTL_DATA_UIO		0x00000800	/* xs_data points to uio */
#define	XS_CTL_DATA_IN		0x00001000	/* data coming into memory */
#define	XS_CTL_DATA_OUT		0x00002000	/* data going out of memory */
#define	XS_CTL_TARGET		0x00004000	/* target mode operation */
#define	XS_CTL_ESCAPE		0x00008000	/* escape operation */
#define	XS_CTL_URGENT		0x00010000	/* urgent (recovery)
						   operation */
#define	XS_CTL_SIMPLE_TAG	0x00020000	/* use a Simple Tag */
#define	XS_CTL_ORDERED_TAG	0x00040000	/* use an Ordered Tag */
#define	XS_CTL_HEAD_TAG		0x00080000	/* use a Head of Queue Tag */
#define	XS_CTL_THAW_PERIPH	0x00100000	/* thaw periph once enqueued */
#define	XS_CTL_FREEZE_PERIPH	0x00200000	/* freeze periph when done */
#define XS_CTL_REQSENSE		0x00800000	/* xfer is a request sense */

#define	XS_CTL_TAGMASK	(XS_CTL_SIMPLE_TAG|XS_CTL_ORDERED_TAG|XS_CTL_HEAD_TAG)

#define	XS_CTL_TAGTYPE(xs)	((xs)->xs_control & XS_CTL_TAGMASK)

/*
 * scsipi_xfer status flags
 */
#define	XS_STS_DONE		0x00000001	/* scsipi_xfer is done */
#define	XS_STS_PRIVATE		0xf0000000	/* reserved for HBA's use */

/*
 * This describes matching information for scsipi_inqmatch().  The more things
 * match, the higher the configuration priority.
 */
struct scsipi_inquiry_pattern {
	u_int8_t type;
	boolean removable;
	const char *vendor;
	const char *product;
	const char *revision;
};

/*
 * This is used to pass information from the high-level configuration code
 * to the device-specific drivers.
 */
struct scsipibus_attach_args {
	struct scsipi_periph *sa_periph;
	struct scsipi_inquiry_pattern sa_inqbuf;
	struct scsipi_inquiry_data *sa_inqptr;
	union {				/* bus-type specific infos */
		u_int8_t scsi_version;	/* SCSI version */
	} scsipi_info;
};

/*
 * this describes a quirk entry
 */
struct scsi_quirk_inquiry_pattern {
	struct scsipi_inquiry_pattern pattern;
	int quirks;
};

/*
 * Default number of retries, used for generic routines.
 */
#define SCSIPIRETRIES 4


#ifdef _KERNEL
void	scsipi_init(void);
void	scsipi_ioctl_init(void);
void	scsipi_load_verbose(void);
int	scsipi_command(struct scsipi_periph *, struct scsipi_generic *, int,
	    u_char *, int, int, int, struct buf *, int);
void	scsipi_create_completion_thread(void *);
const void *scsipi_inqmatch(struct scsipi_inquiry_pattern *, const void *,
	    size_t, size_t, int *);
const char *scsipi_dtype(int);
int	scsipi_execute_xs(struct scsipi_xfer *);
int	scsipi_test_unit_ready(struct scsipi_periph *, int);
int	scsipi_prevent(struct scsipi_periph *, int, int);
int	scsipi_inquire(struct scsipi_periph *,
	    struct scsipi_inquiry_data *, int);
int	scsipi_mode_select(struct scsipi_periph *, int,
	    struct scsi_mode_parameter_header_6 *, int, int, int, int);
int	scsipi_mode_select_big(struct scsipi_periph *, int,
	    struct scsi_mode_parameter_header_10 *, int, int, int, int);
int	scsipi_mode_sense(struct scsipi_periph *, int, int,
	    struct scsi_mode_parameter_header_6 *, int, int, int, int);
int	scsipi_mode_sense_big(struct scsipi_periph *, int, int,
	    struct scsi_mode_parameter_header_10 *, int, int, int, int);
int	scsipi_start(struct scsipi_periph *, int, int);
void	scsipi_done(struct scsipi_xfer *);
void	scsipi_user_done(struct scsipi_xfer *);
int	scsipi_interpret_sense(struct scsipi_xfer *);
void	scsipi_wait_drain(struct scsipi_periph *);
void	scsipi_kill_pending(struct scsipi_periph *);
void    scsipi_get_opcodeinfo(struct scsipi_periph *periph);
void    scsipi_free_opcodeinfo(struct scsipi_periph *periph);
struct scsipi_periph *scsipi_alloc_periph(int);
void	scsipi_free_periph(struct scsipi_periph *);

/* Function pointers for scsiverbose module */
extern int	(*scsipi_print_sense)(struct scsipi_xfer *, int);
extern void	(*scsipi_print_sense_data)(struct scsi_sense_data *, int);

int     scsipi_print_sense_stub(struct scsipi_xfer *, int);
void    scsipi_print_sense_data_stub(struct scsi_sense_data *, int);

extern int	scsi_verbose_loaded;

void	scsipi_print_cdb(struct scsipi_generic *cmd);
int	scsipi_thread_call_callback(struct scsipi_channel *,
	    void (*callback)(struct scsipi_channel *, void *),
	    void *);
void	scsipi_async_event(struct scsipi_channel *,
	    scsipi_async_event_t, void *);
int	scsipi_do_ioctl(struct scsipi_periph *, dev_t, u_long, void *,
	    int, struct lwp *);

void	scsipi_set_xfer_mode(struct scsipi_channel *, int, int);

int	scsipi_channel_init(struct scsipi_channel *);
void	scsipi_channel_shutdown(struct scsipi_channel *);

void	scsipi_insert_periph(struct scsipi_channel *,
	    struct scsipi_periph *);
void	scsipi_remove_periph(struct scsipi_channel *,
	    struct scsipi_periph *);
struct scsipi_periph *scsipi_lookup_periph(struct scsipi_channel *,
	    int, int);
struct scsipi_periph *scsipi_lookup_periph_locked(struct scsipi_channel *,
	    int, int);
int	scsipi_target_detach(struct scsipi_channel *, int, int, int);

int	scsipi_adapter_addref(struct scsipi_adapter *);
void	scsipi_adapter_delref(struct scsipi_adapter *);

void	scsipi_channel_freeze(struct scsipi_channel *, int);
void	scsipi_channel_thaw(struct scsipi_channel *, int);
void	scsipi_channel_timed_thaw(void *);

void	scsipi_periph_freeze(struct scsipi_periph *, int);
void	scsipi_periph_thaw(struct scsipi_periph *, int);
void	scsipi_periph_timed_thaw(void *);

void	scsipi_periph_freeze_locked(struct scsipi_periph *, int);
void	scsipi_periph_thaw_locked(struct scsipi_periph *, int);

int	scsipi_sync_period_to_factor(int);
int	scsipi_sync_factor_to_period(int);
int	scsipi_sync_factor_to_freq(int);

void	show_scsipi_xs(struct scsipi_xfer *);
void	show_scsipi_cmd(struct scsipi_xfer *);
void	show_mem(u_char *, int);
#endif /* _KERNEL */

static __inline void
_lto2b(u_int32_t val, u_int8_t *bytes)
{

	bytes[0] = (val >> 8) & 0xff;
	bytes[1] = val & 0xff;
}

static __inline void
_lto3b(u_int32_t val, u_int8_t *bytes)
{

	bytes[0] = (val >> 16) & 0xff;
	bytes[1] = (val >> 8) & 0xff;
	bytes[2] = val & 0xff;
}

static __inline void
_lto4b(u_int32_t val, u_int8_t *bytes)
{

	bytes[0] = (val >> 24) & 0xff;
	bytes[1] = (val >> 16) & 0xff;
	bytes[2] = (val >> 8) & 0xff;
	bytes[3] = val & 0xff;
}

static __inline void
_lto8b(u_int64_t val, u_int8_t *bytes)
{

	bytes[0] = (val >> 56) & 0xff;
	bytes[1] = (val >> 48) & 0xff;
	bytes[2] = (val >> 40) & 0xff;
	bytes[3] = (val >> 32) & 0xff;
	bytes[4] = (val >> 24) & 0xff;
	bytes[5] = (val >> 16) & 0xff;
	bytes[6] = (val >> 8)  & 0xff;
	bytes[7] = val         & 0xff;
}

static __inline u_int32_t
_2btol(const u_int8_t *bytes)
{
	u_int32_t rv;

	rv = (bytes[0] << 8) |
	     bytes[1];
	return (rv);
}

static __inline u_int32_t
_3btol(const u_int8_t *bytes)
{
	u_int32_t rv;

	rv = (bytes[0] << 16) |
	     (bytes[1] << 8) |
	     bytes[2];
	return (rv);
}

static __inline u_int32_t
_4btol(const u_int8_t *bytes)
{
	u_int32_t rv;

	rv = ((u_int32_t)bytes[0] << 24) |
	     ((u_int32_t)bytes[1] << 16) |
	     ((u_int32_t)bytes[2] << 8) |
	     (u_int32_t)bytes[3];
	return (rv);
}

static __inline u_int64_t
_5btol(const u_int8_t *bytes)
{
	u_int64_t rv;

	rv = ((u_int64_t)bytes[0] << 32) |
	     ((u_int64_t)bytes[1] << 24) |
	     ((u_int64_t)bytes[2] << 16) |
	     ((u_int64_t)bytes[3] << 8) |
	     (u_int64_t)bytes[4];
	return (rv);
}

static __inline u_int64_t
_8btol(const u_int8_t *bytes)
{
	u_int64_t rv;

	rv = ((u_int64_t)bytes[0] << 56) |
	     ((u_int64_t)bytes[1] << 48) |
	     ((u_int64_t)bytes[2] << 40) |
	     ((u_int64_t)bytes[3] << 32) |
	     ((u_int64_t)bytes[4] << 24) |
	     ((u_int64_t)bytes[5] << 16) |
	     ((u_int64_t)bytes[6] << 8) |
	     (u_int64_t)bytes[7];
	return (rv);
}

static __inline void
_lto2l(u_int32_t val, u_int8_t *bytes)
{

	bytes[0] = val & 0xff;
	bytes[1] = (val >> 8) & 0xff;
}

static __inline void
_lto3l(u_int32_t val, u_int8_t *bytes)
{

	bytes[0] = val & 0xff;
	bytes[1] = (val >> 8) & 0xff;
	bytes[2] = (val >> 16) & 0xff;
}

static __inline void
_lto4l(u_int32_t val, u_int8_t *bytes)
{

	bytes[0] = val & 0xff;
	bytes[1] = (val >> 8) & 0xff;
	bytes[2] = (val >> 16) & 0xff;
	bytes[3] = (val >> 24) & 0xff;
}

static __inline u_int32_t
_2ltol(const u_int8_t *bytes)
{
	u_int32_t rv;

	rv = bytes[0] |
	     (bytes[1] << 8);
	return (rv);
}

static __inline u_int32_t
_3ltol(const u_int8_t *bytes)
{
	u_int32_t rv;

	rv = bytes[0] |
	     (bytes[1] << 8) |
	     (bytes[2] << 16);
	return (rv);
}

static __inline u_int32_t
_4ltol(const u_int8_t *bytes)
{
	u_int32_t rv;

	rv = (u_int32_t)bytes[0] |
	     ((u_int32_t)bytes[1] << 8) |
	     ((u_int32_t)bytes[2] << 16) |
	     ((u_int32_t)bytes[3] << 24);
	return (rv);
}

#endif /* _DEV_SCSIPI_SCSIPICONF_H_ */