11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef _SCSI_SCSI_TCQ_H
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define _SCSI_SCSI_TCQ_H
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/blkdev.h>
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_cmnd.h>
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_device.h>
786e33a296c2c9ed6eece0bfff4ac776f42040504James Bottomley#include <scsi/scsi_host.h>
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MSG_SIMPLE_TAG	0x20
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MSG_HEAD_TAG	0x21
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MSG_ORDERED_TAG	0x22
12e66ecd505addaaf40e7d352796ba8d344f6359ddNicholas Bellinger#define MSG_ACA_TAG	0x24	/* unsupported */
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SCSI_NO_TAG	(-1)    /* identify no tag in use */
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
179361401eb7619c033e2394e4f9f6d410d6719ac7David Howells#ifdef CONFIG_BLOCK
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * scsi_get_tag_type - get the type of tag the device supports
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @sdev:	the scsi device
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Notes:
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	If the drive only supports simple tags, returns MSG_SIMPLE_TAG
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	if it supports all tag types, returns MSG_ORDERED_TAG.
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int scsi_get_tag_type(struct scsi_device *sdev)
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!sdev->tagged_supported)
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sdev->ordered_tags)
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return MSG_ORDERED_TAG;
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sdev->simple_tags)
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return MSG_SIMPLE_TAG;
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void scsi_set_tag_type(struct scsi_device *sdev, int tag)
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (tag) {
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MSG_ORDERED_TAG:
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sdev->ordered_tags = 1;
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* fall through */
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MSG_SIMPLE_TAG:
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sdev->simple_tags = 1;
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* fall through */
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sdev->ordered_tags = 0;
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sdev->simple_tags = 0;
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * scsi_activate_tcq - turn on tag command queueing
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @SDpnt:	device to turn on TCQ for
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @depth:	queue depth
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Notes:
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Eventually, I hope depth would be the maximum depth
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	the device could cope with and the real queue depth
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	would be adjustable from 0 to depth.
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds **/
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void scsi_activate_tcq(struct scsi_device *sdev, int depth)
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!sdev->tagged_supported)
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!blk_queue_tagged(sdev->request_queue))
7186e33a296c2c9ed6eece0bfff4ac776f42040504James Bottomley		blk_queue_init_tags(sdev->request_queue, depth,
7286e33a296c2c9ed6eece0bfff4ac776f42040504James Bottomley				    sdev->host->bqt);
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * scsi_deactivate_tcq - turn off tag command queueing
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @SDpnt:	device to turn off TCQ for
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds **/
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void scsi_deactivate_tcq(struct scsi_device *sdev, int depth)
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (blk_queue_tagged(sdev->request_queue))
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		blk_queue_free_tags(sdev->request_queue);
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_adjust_queue_depth(sdev, 0, depth);
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * scsi_populate_tag_msg - place a tag message in a buffer
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @SCpnt:	pointer to the Scsi_Cmnd for the tag
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @msg:	pointer to the area to place the tag
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Notes:
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	designed to create the correct type of tag message for the
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	particular request.  Returns the size of the tag message.
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	May return 0 if TCQ is disabled for this device.
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds **/
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int scsi_populate_tag_msg(struct scsi_cmnd *cmd, char *msg)
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        struct request *req = cmd->request;
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if (blk_rq_tagged(req)) {
1039cbbdca44ae1a6f512ea1e2be11ced8bbb9d430aTejun Heo		*msg++ = MSG_SIMPLE_TAG;
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        	*msg++ = req->tag;
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        	return 2;
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * scsi_find_tag - find a tagged command by device
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @SDpnt:	pointer to the ScSI device
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @tag:	the tag number
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Notes:
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Only works with tags allocated by the generic blk layer.
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds **/
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct scsi_cmnd *scsi_find_tag(struct scsi_device *sdev, int tag)
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        struct request *req;
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if (tag != SCSI_NO_TAG) {
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        	req = blk_queue_find_tag(sdev->request_queue, tag);
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	        return req ? (struct scsi_cmnd *)req->special : NULL;
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* single command, look in space */
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sdev->current_cmnd;
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13386e33a296c2c9ed6eece0bfff4ac776f42040504James Bottomley/**
13486e33a296c2c9ed6eece0bfff4ac776f42040504James Bottomley * scsi_init_shared_tag_map - create a shared tag map
13586e33a296c2c9ed6eece0bfff4ac776f42040504James Bottomley * @shost:	the host to share the tag map among all devices
13686e33a296c2c9ed6eece0bfff4ac776f42040504James Bottomley * @depth:	the total depth of the map
13786e33a296c2c9ed6eece0bfff4ac776f42040504James Bottomley */
138deb81d80ba27da8dfabc29ccb5977db8f4942a0aJames Bottomleystatic inline int scsi_init_shared_tag_map(struct Scsi_Host *shost, int depth)
13986e33a296c2c9ed6eece0bfff4ac776f42040504James Bottomley{
1403070f69b66b7ab2f02d8a2500edae07039c38508Jens Axboe	/*
1413070f69b66b7ab2f02d8a2500edae07039c38508Jens Axboe	 * If the shared tag map isn't already initialized, do it now.
1423070f69b66b7ab2f02d8a2500edae07039c38508Jens Axboe	 * This saves callers from having to check ->bqt when setting up
1433070f69b66b7ab2f02d8a2500edae07039c38508Jens Axboe	 * devices on the shared host (for libata)
1443070f69b66b7ab2f02d8a2500edae07039c38508Jens Axboe	 */
1453070f69b66b7ab2f02d8a2500edae07039c38508Jens Axboe	if (!shost->bqt) {
1463070f69b66b7ab2f02d8a2500edae07039c38508Jens Axboe		shost->bqt = blk_init_tags(depth);
1473070f69b66b7ab2f02d8a2500edae07039c38508Jens Axboe		if (!shost->bqt)
1483070f69b66b7ab2f02d8a2500edae07039c38508Jens Axboe			return -ENOMEM;
1493070f69b66b7ab2f02d8a2500edae07039c38508Jens Axboe	}
1503070f69b66b7ab2f02d8a2500edae07039c38508Jens Axboe
1513070f69b66b7ab2f02d8a2500edae07039c38508Jens Axboe	return 0;
15286e33a296c2c9ed6eece0bfff4ac776f42040504James Bottomley}
15386e33a296c2c9ed6eece0bfff4ac776f42040504James Bottomley
154f583f4924d669d36de677e0cc2422ee95203d444David C Somayajulu/**
155f583f4924d669d36de677e0cc2422ee95203d444David C Somayajulu * scsi_host_find_tag - find the tagged command by host
156f583f4924d669d36de677e0cc2422ee95203d444David C Somayajulu * @shost:	pointer to scsi_host
157f583f4924d669d36de677e0cc2422ee95203d444David C Somayajulu * @tag:	tag of the scsi_cmnd
158f583f4924d669d36de677e0cc2422ee95203d444David C Somayajulu *
159f583f4924d669d36de677e0cc2422ee95203d444David C Somayajulu * Notes:
160f583f4924d669d36de677e0cc2422ee95203d444David C Somayajulu *	Only works with tags allocated by the generic blk layer.
161f583f4924d669d36de677e0cc2422ee95203d444David C Somayajulu **/
162f583f4924d669d36de677e0cc2422ee95203d444David C Somayajulustatic inline struct scsi_cmnd *scsi_host_find_tag(struct Scsi_Host *shost,
163f583f4924d669d36de677e0cc2422ee95203d444David C Somayajulu						int tag)
164f583f4924d669d36de677e0cc2422ee95203d444David C Somayajulu{
165f583f4924d669d36de677e0cc2422ee95203d444David C Somayajulu	struct request *req;
166f583f4924d669d36de677e0cc2422ee95203d444David C Somayajulu
167f583f4924d669d36de677e0cc2422ee95203d444David C Somayajulu	if (tag != SCSI_NO_TAG) {
168f583f4924d669d36de677e0cc2422ee95203d444David C Somayajulu		req = blk_map_queue_find_tag(shost->bqt, tag);
169f583f4924d669d36de677e0cc2422ee95203d444David C Somayajulu		return req ? (struct scsi_cmnd *)req->special : NULL;
170f583f4924d669d36de677e0cc2422ee95203d444David C Somayajulu	}
171f583f4924d669d36de677e0cc2422ee95203d444David C Somayajulu	return NULL;
172f583f4924d669d36de677e0cc2422ee95203d444David C Somayajulu}
173f583f4924d669d36de677e0cc2422ee95203d444David C Somayajulu
1749361401eb7619c033e2394e4f9f6d410d6719ac7David Howells#endif /* CONFIG_BLOCK */
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* _SCSI_SCSI_TCQ_H */
176