scsi_tcq.h 3.2 KB
Newer Older
L
Linus Torvalds 已提交
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
#ifndef _SCSI_SCSI_TCQ_H
#define _SCSI_SCSI_TCQ_H

#include <linux/blkdev.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>


#define MSG_SIMPLE_TAG	0x20
#define MSG_HEAD_TAG	0x21
#define MSG_ORDERED_TAG	0x22

#define SCSI_NO_TAG	(-1)    /* identify no tag in use */



/**
 * scsi_get_tag_type - get the type of tag the device supports
 * @sdev:	the scsi device
 *
 * Notes:
 *	If the drive only supports simple tags, returns MSG_SIMPLE_TAG
 *	if it supports all tag types, returns MSG_ORDERED_TAG.
 */
static inline int scsi_get_tag_type(struct scsi_device *sdev)
{
	if (!sdev->tagged_supported)
		return 0;
	if (sdev->ordered_tags)
		return MSG_ORDERED_TAG;
	if (sdev->simple_tags)
		return MSG_SIMPLE_TAG;
	return 0;
}

static inline void scsi_set_tag_type(struct scsi_device *sdev, int tag)
{
	switch (tag) {
	case MSG_ORDERED_TAG:
		sdev->ordered_tags = 1;
		/* fall through */
	case MSG_SIMPLE_TAG:
		sdev->simple_tags = 1;
		break;
	case 0:
		/* fall through */
	default:
		sdev->ordered_tags = 0;
		sdev->simple_tags = 0;
		break;
	}
}
/**
 * scsi_activate_tcq - turn on tag command queueing
 * @SDpnt:	device to turn on TCQ for
 * @depth:	queue depth
 *
 * Notes:
 *	Eventually, I hope depth would be the maximum depth
 *	the device could cope with and the real queue depth
 *	would be adjustable from 0 to depth.
 **/
static inline void scsi_activate_tcq(struct scsi_device *sdev, int depth)
{
	if (!sdev->tagged_supported)
		return;

	if (!blk_queue_tagged(sdev->request_queue))
		blk_queue_init_tags(sdev->request_queue, depth, NULL);

	scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
}

/**
 * scsi_deactivate_tcq - turn off tag command queueing
 * @SDpnt:	device to turn off TCQ for
 **/
static inline void scsi_deactivate_tcq(struct scsi_device *sdev, int depth)
{
	if (blk_queue_tagged(sdev->request_queue))
		blk_queue_free_tags(sdev->request_queue);
	scsi_adjust_queue_depth(sdev, 0, depth);
}

/**
 * scsi_populate_tag_msg - place a tag message in a buffer
 * @SCpnt:	pointer to the Scsi_Cmnd for the tag
 * @msg:	pointer to the area to place the tag
 *
 * Notes:
 *	designed to create the correct type of tag message for the 
 *	particular request.  Returns the size of the tag message.
 *	May return 0 if TCQ is disabled for this device.
 **/
static inline int scsi_populate_tag_msg(struct scsi_cmnd *cmd, char *msg)
{
        struct request *req = cmd->request;
	struct scsi_device *sdev = cmd->device;

        if (blk_rq_tagged(req)) {
		if (sdev->ordered_tags && req->flags & REQ_HARDBARRIER)
        	        *msg++ = MSG_ORDERED_TAG;
        	else
        	        *msg++ = MSG_SIMPLE_TAG;
        	*msg++ = req->tag;
        	return 2;
	}

	return 0;
}

/**
 * scsi_find_tag - find a tagged command by device
 * @SDpnt:	pointer to the ScSI device
 * @tag:	the tag number
 *
 * Notes:
 *	Only works with tags allocated by the generic blk layer.
 **/
static inline struct scsi_cmnd *scsi_find_tag(struct scsi_device *sdev, int tag)
{

        struct request *req;

        if (tag != SCSI_NO_TAG) {
        	req = blk_queue_find_tag(sdev->request_queue, tag);
	        return req ? (struct scsi_cmnd *)req->special : NULL;
	}

	/* single command, look in space */
	return sdev->current_cmnd;
}

#endif /* _SCSI_SCSI_TCQ_H */