diff options
Diffstat (limited to 'include/scsi/scsi_tcq.h')
-rw-r--r-- | include/scsi/scsi_tcq.h | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/include/scsi/scsi_tcq.h b/include/scsi/scsi_tcq.h new file mode 100644 index 000000000000..e47e36a4ef49 --- /dev/null +++ b/include/scsi/scsi_tcq.h | |||
@@ -0,0 +1,134 @@ | |||
1 | #ifndef _SCSI_SCSI_TCQ_H | ||
2 | #define _SCSI_SCSI_TCQ_H | ||
3 | |||
4 | #include <linux/blkdev.h> | ||
5 | #include <scsi/scsi_cmnd.h> | ||
6 | #include <scsi/scsi_device.h> | ||
7 | |||
8 | |||
9 | #define MSG_SIMPLE_TAG 0x20 | ||
10 | #define MSG_HEAD_TAG 0x21 | ||
11 | #define MSG_ORDERED_TAG 0x22 | ||
12 | |||
13 | #define SCSI_NO_TAG (-1) /* identify no tag in use */ | ||
14 | |||
15 | |||
16 | |||
17 | /** | ||
18 | * scsi_get_tag_type - get the type of tag the device supports | ||
19 | * @sdev: the scsi device | ||
20 | * | ||
21 | * Notes: | ||
22 | * If the drive only supports simple tags, returns MSG_SIMPLE_TAG | ||
23 | * if it supports all tag types, returns MSG_ORDERED_TAG. | ||
24 | */ | ||
25 | static inline int scsi_get_tag_type(struct scsi_device *sdev) | ||
26 | { | ||
27 | if (!sdev->tagged_supported) | ||
28 | return 0; | ||
29 | if (sdev->ordered_tags) | ||
30 | return MSG_ORDERED_TAG; | ||
31 | if (sdev->simple_tags) | ||
32 | return MSG_SIMPLE_TAG; | ||
33 | return 0; | ||
34 | } | ||
35 | |||
36 | static inline void scsi_set_tag_type(struct scsi_device *sdev, int tag) | ||
37 | { | ||
38 | switch (tag) { | ||
39 | case MSG_ORDERED_TAG: | ||
40 | sdev->ordered_tags = 1; | ||
41 | /* fall through */ | ||
42 | case MSG_SIMPLE_TAG: | ||
43 | sdev->simple_tags = 1; | ||
44 | break; | ||
45 | case 0: | ||
46 | /* fall through */ | ||
47 | default: | ||
48 | sdev->ordered_tags = 0; | ||
49 | sdev->simple_tags = 0; | ||
50 | break; | ||
51 | } | ||
52 | } | ||
53 | /** | ||
54 | * scsi_activate_tcq - turn on tag command queueing | ||
55 | * @SDpnt: device to turn on TCQ for | ||
56 | * @depth: queue depth | ||
57 | * | ||
58 | * Notes: | ||
59 | * Eventually, I hope depth would be the maximum depth | ||
60 | * the device could cope with and the real queue depth | ||
61 | * would be adjustable from 0 to depth. | ||
62 | **/ | ||
63 | static inline void scsi_activate_tcq(struct scsi_device *sdev, int depth) | ||
64 | { | ||
65 | if (!sdev->tagged_supported) | ||
66 | return; | ||
67 | |||
68 | if (!blk_queue_tagged(sdev->request_queue)) | ||
69 | blk_queue_init_tags(sdev->request_queue, depth, NULL); | ||
70 | |||
71 | scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); | ||
72 | } | ||
73 | |||
74 | /** | ||
75 | * scsi_deactivate_tcq - turn off tag command queueing | ||
76 | * @SDpnt: device to turn off TCQ for | ||
77 | **/ | ||
78 | static inline void scsi_deactivate_tcq(struct scsi_device *sdev, int depth) | ||
79 | { | ||
80 | if (blk_queue_tagged(sdev->request_queue)) | ||
81 | blk_queue_free_tags(sdev->request_queue); | ||
82 | scsi_adjust_queue_depth(sdev, 0, depth); | ||
83 | } | ||
84 | |||
85 | /** | ||
86 | * scsi_populate_tag_msg - place a tag message in a buffer | ||
87 | * @SCpnt: pointer to the Scsi_Cmnd for the tag | ||
88 | * @msg: pointer to the area to place the tag | ||
89 | * | ||
90 | * Notes: | ||
91 | * designed to create the correct type of tag message for the | ||
92 | * particular request. Returns the size of the tag message. | ||
93 | * May return 0 if TCQ is disabled for this device. | ||
94 | **/ | ||
95 | static inline int scsi_populate_tag_msg(struct scsi_cmnd *cmd, char *msg) | ||
96 | { | ||
97 | struct request *req = cmd->request; | ||
98 | struct scsi_device *sdev = cmd->device; | ||
99 | |||
100 | if (blk_rq_tagged(req)) { | ||
101 | if (sdev->ordered_tags && req->flags & REQ_HARDBARRIER) | ||
102 | *msg++ = MSG_ORDERED_TAG; | ||
103 | else | ||
104 | *msg++ = MSG_SIMPLE_TAG; | ||
105 | *msg++ = req->tag; | ||
106 | return 2; | ||
107 | } | ||
108 | |||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | /** | ||
113 | * scsi_find_tag - find a tagged command by device | ||
114 | * @SDpnt: pointer to the ScSI device | ||
115 | * @tag: the tag number | ||
116 | * | ||
117 | * Notes: | ||
118 | * Only works with tags allocated by the generic blk layer. | ||
119 | **/ | ||
120 | static inline struct scsi_cmnd *scsi_find_tag(struct scsi_device *sdev, int tag) | ||
121 | { | ||
122 | |||
123 | struct request *req; | ||
124 | |||
125 | if (tag != SCSI_NO_TAG) { | ||
126 | req = blk_queue_find_tag(sdev->request_queue, tag); | ||
127 | return req ? (struct scsi_cmnd *)req->special : NULL; | ||
128 | } | ||
129 | |||
130 | /* single command, look in space */ | ||
131 | return sdev->current_cmnd; | ||
132 | } | ||
133 | |||
134 | #endif /* _SCSI_SCSI_TCQ_H */ | ||