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