Commit 7eb141c4 authored by Doug Ledford's avatar Doug Ledford Committed by Linus Torvalds

[PATCH] make SCSI queue depth adjustable

Linus, this has been tested by some people in the field to not break
things, and it's the start of some other changes I'm making, so please put
this in your tree so I'm not merging huge patches but instead am merging a
little as I go.
parent 5c4936fa
This diff is collapsed.
...@@ -46,7 +46,9 @@ ...@@ -46,7 +46,9 @@
eh_host_reset_handler: NULL, \ eh_host_reset_handler: NULL, \
abort: aic7xxx_abort, \ abort: aic7xxx_abort, \
reset: aic7xxx_reset, \ reset: aic7xxx_reset, \
slave_attach: NULL, \ select_queue_depths: NULL, \
slave_attach: aic7xxx_slave_attach, \
slave_detach: aic7xxx_slave_detach, \
bios_param: aic7xxx_biosparam, \ bios_param: aic7xxx_biosparam, \
can_queue: 255, /* max simultaneous cmds */\ can_queue: 255, /* max simultaneous cmds */\
this_id: -1, /* scsi id of host adapter */\ this_id: -1, /* scsi id of host adapter */\
...@@ -64,6 +66,8 @@ extern int aic7xxx_command(Scsi_Cmnd *); ...@@ -64,6 +66,8 @@ extern int aic7xxx_command(Scsi_Cmnd *);
extern int aic7xxx_reset(Scsi_Cmnd *, unsigned int); extern int aic7xxx_reset(Scsi_Cmnd *, unsigned int);
extern int aic7xxx_abort(Scsi_Cmnd *); extern int aic7xxx_abort(Scsi_Cmnd *);
extern int aic7xxx_release(struct Scsi_Host *); extern int aic7xxx_release(struct Scsi_Host *);
extern int aic7xxx_slave_attach(Scsi_Device *);
extern void aic7xxx_slave_detach(Scsi_Device *);
extern const char *aic7xxx_info(struct Scsi_Host *); extern const char *aic7xxx_info(struct Scsi_Host *);
......
...@@ -97,6 +97,10 @@ typedef struct SHT ...@@ -97,6 +97,10 @@ typedef struct SHT
*/ */
int (* detect)(struct SHT *); int (* detect)(struct SHT *);
/*
* This function is only used by one driver and will be going away
* once it switches over to using the slave_detach() function instead.
*/
int (*revoke)(Scsi_Device *); int (*revoke)(Scsi_Device *);
/* Used with loadable modules to unload the host structures. Note: /* Used with loadable modules to unload the host structures. Note:
...@@ -200,11 +204,59 @@ typedef struct SHT ...@@ -200,11 +204,59 @@ typedef struct SHT
int (* reset)(Scsi_Cmnd *, unsigned int); int (* reset)(Scsi_Cmnd *, unsigned int);
/* /*
* This function is used to select synchronous communications, * Once the device has responded to an INQUIRY and we know the device
* which will result in a higher data throughput. Not implemented * is online, call into the low level driver with the Scsi_Device *
* yet. * (so that the low level driver may save it off in a safe location
*/ * for later use in calling scsi_adjust_queue_depth() or possibly
int (* slave_attach)(int, int); * other scsi_* functions) and char * to the INQUIRY return data buffer.
* This way, low level drivers will no longer have to snoop INQUIRY data
* to see if a drive supports PPR message protocol for Ultra160 speed
* negotiations or other similar items. Instead it can simply wait until
* the scsi mid layer calls them with the data in hand and then it can
* do it's checking of INQUIRY data. This will happen once for each new
* device added on this controller (including once for each lun on
* multi-lun devices, so low level drivers should take care to make
* sure that if they do tagged queueing on a per physical unit basis
* instead of a per logical unit basis that they have the mid layer
* allocate tags accordingly).
*
* Things currently recommended to be handled at this time include:
*
* 1. Checking for tagged queueing capability and if able then calling
* scsi_adjust_queue_depth() with the device pointer and the
* suggested new queue depth.
* 2. Checking for things such as SCSI level or DT bit in order to
* determine if PPR message protocols are appropriate on this
* device (or any other scsi INQUIRY data specific things the
* driver wants to know in order to properly handle this device).
* 3. Allocating command structs that the device will need.
* 4. Setting the default timeout on this device (if needed).
* 5. Saving the Scsi_Device pointer so that the low level driver
* will be able to easily call back into scsi_adjust_queue_depth
* again should it be determined that the queue depth for this
* device should be lower or higher than it is initially set to.
* 6. Allocate device data structures as needed that can be attached
* to the Scsi_Device * via SDpnt->host_device_ptr
* 7. Anything else the low level driver might want to do on a device
* specific setup basis...
* 8. Return 0 on success, non-0 on error. The device will be marked
* as offline on error so that no access will occur.
*/
int (* slave_attach)(Scsi_Device *);
/*
* If we are getting ready to remove a device from the scsi chain then
* we call into the low level driver to let them know. Once a low
* level driver has been informed that a drive is going away, the low
* level driver *must* remove it's pointer to the Scsi_Device because
* it is going to be kfree()'ed shortly. It is no longer safe to call
* any mid layer functions with this Scsi_Device *. Additionally, the
* mid layer will not make any more calls into the low level driver's
* queue routine with this device, so it is safe for the device driver
* to deallocate all structs/commands/etc that is has allocated
* specifically for this device at the time of this call.
*/
void (* slave_detach)(Scsi_Device *);
/* /*
* This function determines the bios parameters for a given * This function determines the bios parameters for a given
...@@ -217,6 +269,8 @@ typedef struct SHT ...@@ -217,6 +269,8 @@ typedef struct SHT
/* /*
* Used to set the queue depth for a specific device. * Used to set the queue depth for a specific device.
*
* Once the slave_attach() function is in full use, this will go away.
*/ */
void (*select_queue_depths)(struct Scsi_Host *, Scsi_Device *); void (*select_queue_depths)(struct Scsi_Host *, Scsi_Device *);
......
This diff is collapsed.
...@@ -481,6 +481,7 @@ extern int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt); ...@@ -481,6 +481,7 @@ extern int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt);
extern void scsi_bottom_half_handler(void); extern void scsi_bottom_half_handler(void);
extern void scsi_release_commandblocks(Scsi_Device * SDpnt); extern void scsi_release_commandblocks(Scsi_Device * SDpnt);
extern void scsi_build_commandblocks(Scsi_Device * SDpnt); extern void scsi_build_commandblocks(Scsi_Device * SDpnt);
extern void scsi_adjust_queue_depth(Scsi_Device *, int, int);
extern void scsi_done(Scsi_Cmnd * SCpnt); extern void scsi_done(Scsi_Cmnd * SCpnt);
extern void scsi_finish_command(Scsi_Cmnd *); extern void scsi_finish_command(Scsi_Cmnd *);
extern int scsi_retry_command(Scsi_Cmnd *); extern int scsi_retry_command(Scsi_Cmnd *);
...@@ -563,6 +564,8 @@ struct scsi_device { ...@@ -563,6 +564,8 @@ struct scsi_device {
volatile unsigned short device_busy; /* commands actually active on low-level */ volatile unsigned short device_busy; /* commands actually active on low-level */
Scsi_Cmnd *device_queue; /* queue of SCSI Command structures */ Scsi_Cmnd *device_queue; /* queue of SCSI Command structures */
Scsi_Cmnd *current_cmnd; /* currently active command */ Scsi_Cmnd *current_cmnd; /* currently active command */
unsigned short queue_depth; /* How deep of a queue we have */
unsigned short new_queue_depth; /* How deep of a queue we want */
unsigned int id, lun, channel; unsigned int id, lun, channel;
...@@ -586,24 +589,25 @@ struct scsi_device { ...@@ -586,24 +589,25 @@ struct scsi_device {
unsigned char current_tag; /* current tag */ unsigned char current_tag; /* current tag */
unsigned char sync_min_period; /* Not less than this period */ unsigned char sync_min_period; /* Not less than this period */
unsigned char sync_max_offset; /* Not greater than this offset */ unsigned char sync_max_offset; /* Not greater than this offset */
unsigned char queue_depth; /* How deep a queue to use */
unsigned online:1; unsigned online:1;
unsigned writeable:1; unsigned writeable:1;
unsigned removable:1; unsigned removable:1;
unsigned random:1; unsigned random:1;
unsigned has_cmdblocks:1;
unsigned changed:1; /* Data invalid due to media change */ unsigned changed:1; /* Data invalid due to media change */
unsigned busy:1; /* Used to prevent races */ unsigned busy:1; /* Used to prevent races */
unsigned lockable:1; /* Able to prevent media removal */ unsigned lockable:1; /* Able to prevent media removal */
unsigned borken:1; /* Tell the Seagate driver to be unsigned borken:1; /* Tell the Seagate driver to be
* painfully slow on this device */ * painfully slow on this device */
unsigned tagged_supported:1; /* Supports SCSI-II tagged queuing */
unsigned tagged_queue:1; /* SCSI-II tagged queuing enabled */
unsigned disconnect:1; /* can disconnect */ unsigned disconnect:1; /* can disconnect */
unsigned soft_reset:1; /* Uses soft reset option */ unsigned soft_reset:1; /* Uses soft reset option */
unsigned sync:1; /* Negotiate for sync transfers */ unsigned sdtr:1; /* Device supports SDTR messages */
unsigned wide:1; /* Negotiate for WIDE transfers */ unsigned wdtr:1; /* Device supports WDTR messages */
unsigned ppr:1; /* Device supports PPR messages */
unsigned tagged_supported:1; /* Supports SCSI-II tagged queuing */
unsigned tagged_queue:1; /* SCSI-II tagged queuing enabled */
unsigned simple_tags:1; /* Device supports simple queue tag messages */
unsigned ordered_tags:1;/* Device supports ordered queue tag messages */
unsigned single_lun:1; /* Indicates we should only allow I/O to unsigned single_lun:1; /* Indicates we should only allow I/O to
* one of the luns for the device at a * one of the luns for the device at a
* time. */ * time. */
......
...@@ -1409,6 +1409,14 @@ static int scsi_add_lun(Scsi_Device *sdevscan, Scsi_Device **sdevnew, ...@@ -1409,6 +1409,14 @@ static int scsi_add_lun(Scsi_Device *sdevscan, Scsi_Device **sdevnew,
sdev->lockable = sdev->removable; sdev->lockable = sdev->removable;
sdev->soft_reset = (inq_result[7] & 1) && ((inq_result[3] & 7) == 2); sdev->soft_reset = (inq_result[7] & 1) && ((inq_result[3] & 7) == 2);
if (sdev->scsi_level >= SCSI_3 || (sdev->inquiry_len > 56 &&
inq_result[56] & 0x04))
sdev->ppr = 1;
if (inq_result[7] & 0x60)
sdev->wdtr = 1;
if (inq_result[7] & 0x10)
sdev->sdtr = 1;
/* /*
* XXX maybe move the identifier and driverfs/devfs setup to a new * XXX maybe move the identifier and driverfs/devfs setup to a new
* function, and call them after this function is called. * function, and call them after this function is called.
...@@ -1513,9 +1521,9 @@ static int scsi_probe_and_add_lun(Scsi_Device *sdevscan, Scsi_Device **sdevnew, ...@@ -1513,9 +1521,9 @@ static int scsi_probe_and_add_lun(Scsi_Device *sdevscan, Scsi_Device **sdevnew,
* XXX maybe change scsi_release_commandblocks to not reset * XXX maybe change scsi_release_commandblocks to not reset
* queue_depth to 0. * queue_depth to 0.
*/ */
sdevscan->queue_depth = 1; sdevscan->new_queue_depth = 1;
scsi_build_commandblocks(sdevscan); scsi_build_commandblocks(sdevscan);
if (sdevscan->has_cmdblocks == 0) if (sdevscan->queue_depth == 0)
goto alloc_failed; goto alloc_failed;
sreq = scsi_allocate_request(sdevscan); sreq = scsi_allocate_request(sdevscan);
...@@ -1589,7 +1597,7 @@ static int scsi_probe_and_add_lun(Scsi_Device *sdevscan, Scsi_Device **sdevnew, ...@@ -1589,7 +1597,7 @@ static int scsi_probe_and_add_lun(Scsi_Device *sdevscan, Scsi_Device **sdevnew,
kfree(scsi_result); kfree(scsi_result);
if (sreq != NULL) if (sreq != NULL)
scsi_release_request(sreq); scsi_release_request(sreq);
if (sdevscan->has_cmdblocks != 0) if (sdevscan->queue_depth != 0)
scsi_release_commandblocks(sdevscan); scsi_release_commandblocks(sdevscan);
return SCSI_SCAN_NO_RESPONSE; return SCSI_SCAN_NO_RESPONSE;
} }
...@@ -1743,9 +1751,9 @@ static int scsi_report_lun_scan(Scsi_Device *sdevscan) ...@@ -1743,9 +1751,9 @@ static int scsi_report_lun_scan(Scsi_Device *sdevscan)
if (sdevscan->scsi_level < SCSI_3) if (sdevscan->scsi_level < SCSI_3)
return 1; return 1;
sdevscan->queue_depth = 1; sdevscan->new_queue_depth = 1;
scsi_build_commandblocks(sdevscan); scsi_build_commandblocks(sdevscan);
if (sdevscan->has_cmdblocks == 0) { if (sdevscan->queue_depth == 0) {
printk(ALLOC_FAILURE_MSG, __FUNCTION__); printk(ALLOC_FAILURE_MSG, __FUNCTION__);
/* /*
* We are out of memory, don't try scanning any further. * We are out of memory, don't try scanning any further.
...@@ -2018,6 +2026,17 @@ static void scsi_scan_selected_lun(struct Scsi_Host *shost, uint channel, ...@@ -2018,6 +2026,17 @@ static void scsi_scan_selected_lun(struct Scsi_Host *shost, uint channel,
*/ */
if (shost->select_queue_depths != NULL) if (shost->select_queue_depths != NULL)
(shost->select_queue_depths) (shost, shost->host_queue); (shost->select_queue_depths) (shost, shost->host_queue);
if (shost->hostt->slave_attach != NULL)
if ((shost->hostt->slave_attach) (sdev) != 0) {
/*
* Low level driver failed to attach this
* device, we've got to kick it back out
* now as a result :-(
*/
printk("scsi_scan_selected_lun: slave_attach "
"failed, marking device OFFLINE.\n");
sdev->online = FALSE;
}
for (sdt = scsi_devicelist; sdt; sdt = sdt->next) for (sdt = scsi_devicelist; sdt; sdt = sdt->next)
if (sdt->init && sdt->dev_noticed) if (sdt->init && sdt->dev_noticed)
...@@ -2028,7 +2047,7 @@ static void scsi_scan_selected_lun(struct Scsi_Host *shost, uint channel, ...@@ -2028,7 +2047,7 @@ static void scsi_scan_selected_lun(struct Scsi_Host *shost, uint channel,
(*sdt->attach) (sdev); (*sdt->attach) (sdev);
if (sdev->attached) { if (sdev->attached) {
scsi_build_commandblocks(sdev); scsi_build_commandblocks(sdev);
if (sdev->has_cmdblocks == 0) if (sdev->queue_depth == 0)
printk(ALLOC_FAILURE_MSG, printk(ALLOC_FAILURE_MSG,
__FUNCTION__); __FUNCTION__);
} }
......
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