Commit 8c0b740d authored by James Bottomley's avatar James Bottomley

[SCSI mid-layer]

Add support for generic blk layer TCQ (needs blk_queue_find_tag
function)
parent 838ede57
......@@ -562,6 +562,26 @@ extern int scsi_unregister_host(Scsi_Host_Template *);
#define SD_EXTRA_DEVS CONFIG_SD_EXTRA_DEVS
#define SR_EXTRA_DEVS CONFIG_SR_EXTRA_DEVS
/**
* scsi_find_device - find a device given the host
* @channel: SCSI channel (zero if only one channel)
* @pun: SCSI target number (physical unit number)
* @lun: SCSI Logical Unit Number
**/
static inline Scsi_Device *scsi_find_device(struct Scsi_Host *host,
int channel, int pun, int lun) {
Scsi_Device *SDpnt;
for(SDpnt = host->host_queue;
SDpnt != NULL;
SDpnt = SDpnt->next)
if(SDpnt->channel == channel && SDpnt->id == pun
&& SDpnt->lun ==lun)
break;
return SDpnt;
}
#endif
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
......
......@@ -254,11 +254,20 @@ __setup("scsi_logging=", scsi_logging_setup);
static void scsi_wait_done(Scsi_Cmnd * SCpnt)
{
struct request *req;
struct request *req = SCpnt->request;
struct request_queue *q = &SCpnt->device->request_queue;
unsigned long flags;
req = SCpnt->request;
ASSERT_LOCK(q->queue_lock, 0);
req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */
spin_lock_irqsave(q->queue_lock, flags);
if(blk_rq_tagged(req))
blk_queue_end_tag(q, req);
spin_unlock_irqrestore(q->queue_lock, flags);
if (req->waiting)
complete(req->waiting);
}
......
......@@ -560,6 +560,7 @@ struct scsi_device {
atomic_t device_active; /* commands checked out for device */
volatile unsigned short device_busy; /* commands actually active on low-level */
Scsi_Cmnd *device_queue; /* queue of SCSI Command structures */
Scsi_Cmnd *current_cmnd; /* currently active command */
unsigned int id, lun, channel;
......@@ -861,12 +862,12 @@ extern int scsi_reset_provider(Scsi_Device *, int);
* would be adjustable from 0 to depth.
**/
static inline void scsi_activate_tcq(Scsi_Device *SDpnt, int depth) {
request_queue_t *q = &SDpnt->request_queue;
request_queue_t *q = &SDpnt->request_queue;
if(SDpnt->tagged_supported && !blk_queue_tagged(q)) {
blk_queue_init_tags(q, depth);
SDpnt->tagged_queue = 1;
}
if(SDpnt->tagged_supported && !blk_queue_tagged(q)) {
blk_queue_init_tags(q, depth);
SDpnt->tagged_queue = 1;
}
}
/**
......@@ -874,13 +875,15 @@ static inline void scsi_activate_tcq(Scsi_Device *SDpnt, int depth) {
* @SDpnt: device to turn off TCQ for
**/
static inline void scsi_deactivate_tcq(Scsi_Device *SDpnt) {
blk_queue_free_tags(&SDpnt->request_queue);
SDpnt->tagged_queue = 0;
blk_queue_free_tags(&SDpnt->request_queue);
SDpnt->tagged_queue = 0;
}
#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_populate_tag_msg - place a tag message in a buffer
* @SCpnt: pointer to the Scsi_Cmnd for the tag
......@@ -892,21 +895,44 @@ static inline void scsi_deactivate_tcq(Scsi_Device *SDpnt) {
* May return 0 if TCQ is disabled for this device.
**/
static inline int scsi_populate_tag_msg(Scsi_Cmnd *SCpnt, char *msg) {
struct request *req = SCpnt->request;
struct request *req = SCpnt->request;
if(!blk_rq_tagged(req))
return 0;
if(!blk_rq_tagged(req))
return 0;
if(req->flags & REQ_BARRIER)
*msg++ = MSG_ORDERED_TAG;
else
*msg++ = MSG_SIMPLE_TAG;
if(req->flags & REQ_BARRIER)
*msg++ = MSG_ORDERED_TAG;
else
*msg++ = MSG_SIMPLE_TAG;
*msg++ = SCpnt->request->tag;
*msg++ = SCpnt->request->tag;
return 2;
return 2;
}
/**
* 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 Scsi_Cmnd *scsi_find_tag(Scsi_Device *SDpnt, int tag) {
struct request *req;
if(tag == SCSI_NO_TAG)
/* single command, look in space */
return SDpnt->current_cmnd;
req = blk_queue_find_tag(&SDpnt->request_queue, tag);
if(req == NULL)
return NULL;
return (Scsi_Cmnd *)req->special;
}
#endif
......
......@@ -76,7 +76,8 @@ static void __scsi_insert_special(request_queue_t *q, struct request *rq,
* must not attempt merges on this) and that it acts as a soft
* barrier
*/
rq->flags = REQ_SPECIAL | REQ_BARRIER;
rq->flags &= REQ_QUEUED;
rq->flags |= REQ_SPECIAL | REQ_BARRIER;
rq->special = data;
......@@ -87,6 +88,9 @@ static void __scsi_insert_special(request_queue_t *q, struct request *rq,
* device, or a host that is unable to accept a particular command.
*/
spin_lock_irqsave(q->queue_lock, flags);
/* If command is tagged, release the tag */
if(blk_rq_tagged(rq))
blk_queue_end_tag(q, rq);
_elv_add_request(q, rq, !at_head, 0);
q->request_fn(q);
spin_unlock_irqrestore(q->queue_lock, flags);
......@@ -927,11 +931,13 @@ void scsi_request_fn(request_queue_t * q)
* reason to search the list, because all of the commands
* in this queue are for the same device.
*/
if(blk_queue_tagged(q))
blk_queue_start_tag(q, req);
else
if(!(blk_queue_tagged(q) && (blk_queue_start_tag(q, req) == 0)))
blkdev_dequeue_request(req);
/* note the overloading of req->special. When the tag
* is active it always means SCpnt. If the tag goes
* back for re-queueing, it may be reset */
req->special = SCpnt;
SCpnt->request = req;
/*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment