* ^[$B!y^[(B10000^[$B1_J,L5NA!y^[(B
From: info @ 2005-04-13 4:10 UTC (permalink / raw)
To: linux-scsi
^[$B"#"#"#!V^[(B10000^[$B1_!WJ,L5NA%]%$%s%HB#Dh%-%c%s%Z!<%s<B;\Cf!*"#"#"#^[(B
^[$B$3$N=U$N=P2q$$$r6/NO$K;Y1g$7$^$9!*^[(B
^[$B:#$9$0EPO?$7$FD:$$$?J}$K$O!";O$a$K^[(B10000^[$B1_J,$N%]%$%s%H$rL5NA$G:9$7>e$2$^$9!*^[(B
^[$B"!^[(B10000^[$B1_L5NA%]%$%s%H$H?7$7$$=P2q$$^[(BGET^[$B!*"*"*"*^[(B http://awg.qsv20.com/?springk
^[$B!zL5NA$GAjEvM7$Y$^$9$N$G@'Hs$*;n$72<$5$$$M"v^[(B
^[$B!z;HMQ$7$F$_$F!V$3$l$O!*!W$H;W$C$FD:$$$?J}$N$_!VM-NA!W$X$*?J$_2<$5$$!#^[(B
^ permalink raw reply
* Re: CiAllis WALLIUM Wiagra
From: Alexis Reed @ 2005-04-13 2:02 UTC (permalink / raw)
To: Alexis Reed
Re: Va11ium Ci-alis Vi-agra
http://ofkvetkgf6lrhs7o78z6ea7o.bhwittalii.com/
^ permalink raw reply
* Re: evaluation of scsi_cmnd->resid
From: Douglas Gilbert @ 2005-04-12 21:38 UTC (permalink / raw)
To: Andreas Herrmann; +Cc: Linux SCSI
In-Reply-To: <20050412180443.GA7395@lion28.boeblingen.de.ibm.com>
Andreas Herrmann wrote:
> Hi,
>
> Am I right in the assumption that scsi_cmnd->resid is just of use for
> requests initiated by sg?
>
> How does the SCSI-stack handle normal (non-sg) requests for SCSI disks
> for which a scsi_cmnd->resid is set? AFAIK, resid is ignored by
> sd. So, such requests are returned to the block layer although the
> amount of data transferred is less the amount of data that should have
> been transferred. For FCP-drivers this means that some error situations
> cannot be handled by just using scsi_cmnd->resid.
>
> What am I missing here?
Andreas,
sd, sr, st, ch and osst (and the mid level when it issues
SCSI commands) need to be modified to use resid.
resid is initialized to zero (by the mid level). So older
LLDs that do not set resid will not change the current
situation for the ULDs mentioned above :-)
Doug Gilbert
^ permalink raw reply
* Re: [patch 062/198] ahci: AHCI mode SATA patch for Intel ESB2
From: Jeff Garzik @ 2005-04-12 18:32 UTC (permalink / raw)
To: akpm; +Cc: torvalds, linux-kernel, jason.d.gaston, linux-scsi
In-Reply-To: <200504121031.j3CAVexS005372@shell0.pdx.osdl.net>
On Tue, Apr 12, 2005 at 03:31:34AM -0700, akpm@osdl.org wrote:
>
> From: Jason Gaston <jason.d.gaston@intel.com>
>
> This patch adds the Intel ESB2 DID's to the ahci.c file for AHCI mode SATA
> support.
Please don't send libata stuff directly to Linus.
Even a patch that appears as simple as this has complications:
The Intel ICH7 combined mode still needs sorting out; combined mode and
another BIOS option (IDE/AHCI) can change the PCI IDs that the
southbridge exports.
I don't want to commit support for -half- the configurations, which
oh-by-the-way will fail if even those users tweak the BIOS options.
Jeff
^ permalink raw reply
* evaluation of scsi_cmnd->resid
From: Andreas Herrmann @ 2005-04-12 18:04 UTC (permalink / raw)
To: Linux SCSI
Hi,
Am I right in the assumption that scsi_cmnd->resid is just of use for
requests initiated by sg?
How does the SCSI-stack handle normal (non-sg) requests for SCSI disks
for which a scsi_cmnd->resid is set? AFAIK, resid is ignored by
sd. So, such requests are returned to the block layer although the
amount of data transferred is less the amount of data that should have
been transferred. For FCP-drivers this means that some error situations
cannot be handled by just using scsi_cmnd->resid.
What am I missing here?
Regards,
Andreas
^ permalink raw reply
* RE: [PATCH] mptscsih: MODULE_PARM() -> module_param()
From: James Bottomley @ 2005-04-12 16:38 UTC (permalink / raw)
To: Moore, Eric Dean; +Cc: Magnus Damm, SCSI Mailing List, mpt_linux_developer
In-Reply-To: <91888D455306F94EBD4D168954A9457C01DBBC2C@nacos172.co.lsil.com>
On Tue, 2005-04-05 at 14:30 -0600, Moore, Eric Dean wrote:
> Ok fine - This fix is already there in the series of patches
> I provided a week ago for splitting the mpt fusion drivers
> into seperate bus type drivers.
>
> James any word on whether those series of patches will get
> approved?
The patches themselves look fine. However, there's a problem which I
just discovered on putting it together and taking it for a test spin:
the MODULE_DEVICE_TABLE directive is still in mptbase. This means that
the udev/hotplug system thinks that when it's loaded mptbase
everything's done, which now means that everyone loses their devices
since the upper drivers aren't loaded. To make this all work and keep
the distros happy, the MODULE_DEVICE_TABLE has to be split out and
placed into the mptspi or mptfc components.
James
^ permalink raw reply
* Re: [ANNOUNCE 2/6] Linux-iSCSI High-Performance Initiator
From: Dmitry Yusupov @ 2005-04-12 16:34 UTC (permalink / raw)
To: Greg KH; +Cc: Alex Aizman, linux-scsi, linux-kernel
In-Reply-To: <20050412053532.GE32372@kroah.com>
On Mon, 2005-04-11 at 22:35 -0700, Greg KH wrote:
> On Mon, Apr 11, 2005 at 08:24:08PM -0700, Alex Aizman wrote:
> > +typedef uint64_t iscsi_snx_t; /* iSCSI Data-Path session handle */
> > +typedef uint64_t iscsi_cnx_t; /* iSCSI Data-Path connection handle */
>
> Do you really have to create a new typedef? Please reconsider. Just
> use u64 everywhere, unless you need to do type checking...
it is a handle and it is used as a parameter in exported API. yes. type
checking exactly the reason.
Dima
^ permalink raw reply
* [PATCH] add DID_REQUEUE to the error handling
From: James Bottomley @ 2005-04-12 15:17 UTC (permalink / raw)
To: SCSI Mailing List
We have a DID_IMM_RETRY to require a retry at once, but we could do with
a DID_REQUEUE to instruct the mid-layer to treat this command in the
same manner as QUEUE_FULL or BUSY (i.e. halt the submission until
another command returns ... or the queue pressure builds if there are no
outstanding commands).
James
===== drivers/scsi/scsi_error.c 1.91 vs edited =====
--- 1.91/drivers/scsi/scsi_error.c 2005-03-31 03:06:21 -06:00
+++ edited/drivers/scsi/scsi_error.c 2005-04-12 10:04:51 -05:00
@@ -1306,6 +1306,9 @@
case DID_IMM_RETRY:
return NEEDS_RETRY;
+ case DID_REQUEUE:
+ return ADD_TO_MLQUEUE;
+
case DID_ERROR:
if (msg_byte(scmd->result) == COMMAND_COMPLETE &&
status_byte(scmd->result) == RESERVATION_CONFLICT)
===== include/scsi/scsi.h 1.28 vs edited =====
--- 1.28/include/scsi/scsi.h 2005-03-29 09:53:44 -06:00
+++ edited/include/scsi/scsi.h 2005-04-12 10:02:47 -05:00
@@ -295,6 +295,8 @@
#define DID_PASSTHROUGH 0x0a /* Force command past mid-layer */
#define DID_SOFT_ERROR 0x0b /* The low level driver just wish a retry */
#define DID_IMM_RETRY 0x0c /* Retry without decrementing retry count */
+#define DID_REQUEUE 0x0d /* Requeue command (no immediate retry) also
+ * without decrementing the retry count */
#define DRIVER_OK 0x00 /* Driver status */
/*
^ permalink raw reply
* Re: [PATCH scsi-misc-2.6 06/07] scsi: add cmd->result clearing
From: Tejun Heo @ 2005-04-12 12:52 UTC (permalink / raw)
To: James.Bottomley, axboe, Christoph Hellwig; +Cc: linux-scsi, linux-kernel
In-Reply-To: <20050412125219.88E5C1F6@htj.dyndns.org>
06_scsi_requeue_reset_result.patch
cmd->result wasn't cleared on requeue or reprep. Clear it.
Signed-off-by: Tejun Heo <htejun@gmail.com>
scsi.c | 9 +++++----
scsi_lib.c | 1 +
2 files changed, 6 insertions(+), 4 deletions(-)
Index: scsi-reqfn-export/drivers/scsi/scsi.c
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi.c 2005-04-12 21:50:11.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi.c 2005-04-12 21:50:12.000000000 +0900
@@ -681,11 +681,12 @@ void scsi_retry_command(struct scsi_cmnd
*/
scsi_setup_cmd_retry(cmd);
- /*
- * Zero the sense information from the last time we tried
- * this command.
- */
+ /*
+ * Zero the sense information and result code from the last
+ * time we tried this command.
+ */
memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+ cmd->result = 0;
scsi_requeue_command(cmd);
}
Index: scsi-reqfn-export/drivers/scsi/scsi_lib.c
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi_lib.c 2005-04-12 21:50:12.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi_lib.c 2005-04-12 21:50:12.000000000 +0900
@@ -222,6 +222,7 @@ static int scsi_init_cmd_errh(struct scs
cmd->abort_reason = 0;
memset(cmd->sense_buffer, 0, sizeof cmd->sense_buffer);
+ cmd->result = 0;
if (cmd->cmd_len == 0)
cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
^ permalink raw reply
* Re: [PATCH scsi-misc-2.6 07/07] scsi: consolidate scsi_cmd_retry() calls
From: Tejun Heo @ 2005-04-12 12:52 UTC (permalink / raw)
To: James.Bottomley, axboe, Christoph Hellwig; +Cc: linux-scsi, linux-kernel
In-Reply-To: <20050412125219.88E5C1F6@htj.dyndns.org>
07_scsi_requeue_consolidate_setup_cmd_retry_calls_in_eh.patch
scsi_setup_cmd_retry() is needed because scsi eh may alter
scsi_cmnd to issue eh commands. Consolidate calls to
scsi_setup_cmd_retry() to one place in scsi_eh_flush_done_q().
This change makes scsi_retry_command() more symmetrical with
scsi_finish_command().
Signed-off-by: Tejun Heo <htejun@gmail.com>
scsi.c | 5 -----
scsi_error.c | 31 +++++++------------------------
2 files changed, 7 insertions(+), 29 deletions(-)
Index: scsi-reqfn-export/drivers/scsi/scsi.c
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi.c 2005-04-12 21:50:12.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi.c 2005-04-12 21:50:12.000000000 +0900
@@ -677,11 +677,6 @@ void scsi_retry_command(struct scsi_cmnd
scsi_device_unbusy(cmd->device);
/*
- * Restore the SCSI command state.
- */
- scsi_setup_cmd_retry(cmd);
-
- /*
* Zero the sense information and result code from the last
* time we tried this command.
*/
Index: scsi-reqfn-export/drivers/scsi/scsi_error.c
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi_error.c 2005-04-12 21:50:11.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi_error.c 2005-04-12 21:50:12.000000000 +0900
@@ -586,11 +586,6 @@ static int scsi_request_sense(struct scs
kfree(scsi_result);
- /*
- * when we eventually call scsi_finish, we really wish to complete
- * the original request, so let's restore the original data. (db)
- */
- scsi_setup_cmd_retry(scmd);
scmd->result = saved_result;
return rtn;
}
@@ -612,14 +607,7 @@ static void scsi_eh_finish_cmd(struct sc
{
scmd->device->host->host_failed--;
scmd->state = SCSI_STATE_BHQUEUE;
-
scsi_eh_eflags_clr_all(scmd);
-
- /*
- * set this back so that the upper level can correctly free up
- * things.
- */
- scsi_setup_cmd_retry(scmd);
list_move_tail(&scmd->eh_entry, done_q);
}
@@ -756,12 +744,6 @@ retry_tur:
rtn = scsi_send_eh_cmnd(scmd, SENSE_TIMEOUT);
/*
- * when we eventually call scsi_finish, we really wish to complete
- * the original request, so let's restore the original data. (db)
- */
- scsi_setup_cmd_retry(scmd);
-
- /*
* hey, we are done. let's look to see what happened.
*/
SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd %p rtn %x\n",
@@ -884,12 +866,6 @@ static int scsi_eh_try_stu(struct scsi_c
rtn = scsi_send_eh_cmnd(scmd, START_UNIT_TIMEOUT);
/*
- * when we eventually call scsi_finish, we really wish to complete
- * the original request, so let's restore the original data. (db)
- */
- scsi_setup_cmd_retry(scmd);
-
- /*
* hey, we are done. let's look to see what happened.
*/
SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd %p rtn %x\n",
@@ -1515,6 +1491,13 @@ static void scsi_eh_flush_done_q(struct
list_for_each_safe(lh, lh_sf, done_q) {
scmd = list_entry(lh, struct scsi_cmnd, eh_entry);
list_del_init(lh);
+
+ /*
+ * Restore the SCSI command state such that we retry
+ * or finish the original command.
+ */
+ scsi_setup_cmd_retry(scmd);
+
if (scsi_device_online(scmd->device) &&
!blk_noretry_request(scmd->request) &&
(++scmd->retries < scmd->allowed)) {
^ permalink raw reply
* Re: [PATCH scsi-misc-2.6 05/07] scsi: move scsi_init_cmd_errh() from request_fn to prep_fn.
From: Tejun Heo @ 2005-04-12 12:52 UTC (permalink / raw)
To: James.Bottomley, axboe, Christoph Hellwig; +Cc: linux-scsi, linux-kernel
In-Reply-To: <20050412125219.88E5C1F6@htj.dyndns.org>
05_scsi_requeue_move_init_cmd_errh.patch
As now all non-reprepped requeue goes through
scsi_retry_command() which clears sense buffer, there's no
need to call scsi_init_cmd_errh() in scsi_request_fn(). Move
scsi_init_cmd_errh() to scsi_prep_fn().
Signed-off-by: Tejun Heo <htejun@gmail.com>
scsi_lib.c | 5 ++---
1 files changed, 2 insertions(+), 3 deletions(-)
Index: scsi-reqfn-export/drivers/scsi/scsi_lib.c
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi_lib.c 2005-04-12 21:50:11.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi_lib.c 2005-04-12 21:50:12.000000000 +0900
@@ -1051,6 +1051,8 @@ static int scsi_prep_fn(struct request_q
if (CDB_SIZE(cmd) > sdev->host->max_cmd_len)
goto kill;
+ scsi_init_cmd_errh(cmd);
+
/* If SCSI-2 or lower, store the LUN value in cmnd. */
if (cmd->device->scsi_level <= SCSI_2)
cmd->cmnd[1] = (cmd->cmnd[1] & 0x1f) |
@@ -1311,9 +1313,6 @@ static void scsi_request_fn(struct reque
target->starget_sdev_user = sdev;
}
- /* Once requeue path is cleaned up, init_cmd_errh can
- * be moved to prep_fn() where it belongs. */
- scsi_init_cmd_errh(cmd);
shost->host_busy++;
scsi_log_send(cmd);
scsi_cmd_get_serial(shost, cmd);
^ permalink raw reply
* Re: [PATCH scsi-misc-2.6 03/07] scsi: replace scsi_queue_insert() usages with scsi_retry_command()
From: Tejun Heo @ 2005-04-12 12:52 UTC (permalink / raw)
To: James.Bottomley, axboe, Christoph Hellwig; +Cc: linux-scsi, linux-kernel
In-Reply-To: <20050412125219.88E5C1F6@htj.dyndns.org>
03_scsi_requeue_use_scsi_retry_command_instead_of_scsi_queue_insert.patch
There are two users of scsi_queue_insert() left now. One in
scsi_softirq() and the other in scsi_eh_flush_done_q(). The
only additional functionality of scsi_queue_insert() used is
setting device_blocked on ADD_TO_MLQUEUE case in
scsi_softirq().
Open code device_blocked setting and replace
scsi_queue_insert() with scsi_retry_command() in both cases.
Signed-off-by: Tejun Heo <htejun@gmail.com>
scsi.c | 7 ++++---
scsi_error.c | 2 +-
2 files changed, 5 insertions(+), 4 deletions(-)
Index: scsi-reqfn-export/drivers/scsi/scsi.c
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi.c 2005-04-12 21:50:11.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi.c 2005-04-12 21:50:11.000000000 +0900
@@ -638,6 +638,7 @@ static void scsi_softirq(struct softirq_
while (!list_empty(&local_q)) {
struct scsi_cmnd *cmd = list_entry(local_q.next,
struct scsi_cmnd, eh_entry);
+ struct scsi_device *sdev = cmd->device;
list_del_init(&cmd->eh_entry);
disposition = scsi_decide_disposition(cmd);
@@ -646,12 +647,12 @@ static void scsi_softirq(struct softirq_
case SUCCESS:
scsi_finish_command(cmd);
break;
+ case ADD_TO_MLQUEUE:
+ sdev->device_blocked = sdev->max_device_blocked;
+ /* fall through */
case NEEDS_RETRY:
scsi_retry_command(cmd);
break;
- case ADD_TO_MLQUEUE:
- scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
- break;
default:
if (!scsi_eh_scmd_add(cmd, 0))
scsi_finish_command(cmd);
Index: scsi-reqfn-export/drivers/scsi/scsi_error.c
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi_error.c 2005-04-12 21:50:10.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi_error.c 2005-04-12 21:50:11.000000000 +0900
@@ -1522,7 +1522,7 @@ static void scsi_eh_flush_done_q(struct
" retry cmd: %p\n",
current->comm,
scmd));
- scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY);
+ scsi_retry_command(scmd);
} else {
if (!scmd->result)
scmd->result |= (DRIVER_TIMEOUT << 24);
^ permalink raw reply
* Re: [PATCH scsi-misc-2.6 04/07] scsi: remove scsi_queue_insert()
From: Tejun Heo @ 2005-04-12 12:52 UTC (permalink / raw)
To: James.Bottomley, axboe, Christoph Hellwig; +Cc: linux-scsi, linux-kernel
In-Reply-To: <20050412125219.88E5C1F6@htj.dyndns.org>
04_scsi_requeue_remove_scsi_queue_insert.patch
scsi_queue_insert() now has no user left. Kill it.
Signed-off-by: Tejun Heo <htejun@gmail.com>
scsi_lib.c | 76 ------------------------------------------------------------
scsi_priv.h | 1
2 files changed, 77 deletions(-)
Index: scsi-reqfn-export/drivers/scsi/scsi_lib.c
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi_lib.c 2005-04-12 21:50:11.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi_lib.c 2005-04-12 21:50:11.000000000 +0900
@@ -106,82 +106,6 @@ int scsi_insert_special_req(struct scsi_
return 0;
}
-static void scsi_run_queue(struct request_queue *q);
-
-/*
- * Function: scsi_queue_insert()
- *
- * Purpose: Insert a command in the midlevel queue.
- *
- * Arguments: cmd - command that we are adding to queue.
- * reason - why we are inserting command to queue.
- *
- * Lock status: Assumed that lock is not held upon entry.
- *
- * Returns: Nothing.
- *
- * Notes: We do this for one of two cases. Either the host is busy
- * and it cannot accept any more commands for the time being,
- * or the device returned QUEUE_FULL and can accept no more
- * commands.
- * Notes: This could be called either from an interrupt context or a
- * normal process context.
- */
-int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
-{
- struct Scsi_Host *host = cmd->device->host;
- struct scsi_device *device = cmd->device;
- struct request_queue *q = device->request_queue;
- unsigned long flags;
-
- SCSI_LOG_MLQUEUE(1,
- printk("Inserting command %p into mlqueue\n", cmd));
-
- /*
- * Set the appropriate busy bit for the device/host.
- *
- * If the host/device isn't busy, assume that something actually
- * completed, and that we should be able to queue a command now.
- *
- * Note that the prior mid-layer assumption that any host could
- * always queue at least one command is now broken. The mid-layer
- * will implement a user specifiable stall (see
- * scsi_host.max_host_blocked and scsi_device.max_device_blocked)
- * if a command is requeued with no other commands outstanding
- * either for the device or for the host.
- */
- if (reason == SCSI_MLQUEUE_HOST_BUSY)
- host->host_blocked = host->max_host_blocked;
- else if (reason == SCSI_MLQUEUE_DEVICE_BUSY)
- device->device_blocked = device->max_device_blocked;
-
- /*
- * Register the fact that we own the thing for now.
- */
- cmd->state = SCSI_STATE_MLQUEUE;
- cmd->owner = SCSI_OWNER_MIDLEVEL;
-
- /*
- * Decrement the counters, since these commands are no longer
- * active on the host/device.
- */
- scsi_device_unbusy(device);
-
- /*
- * Requeue the command. Turn on REQ_SOFTBARRIER to prevent
- * other requests from passing this request.
- */
- cmd->request->flags |= REQ_SOFTBARRIER;
-
- spin_lock_irqsave(q->queue_lock, flags);
- blk_requeue_request(q, cmd->request);
- spin_unlock_irqrestore(q->queue_lock, flags);
-
- scsi_run_queue(q);
-
- return 0;
-}
-
/*
* Function: scsi_do_req
*
Index: scsi-reqfn-export/drivers/scsi/scsi_priv.h
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi_priv.h 2005-04-12 21:50:11.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi_priv.h 2005-04-12 21:50:11.000000000 +0900
@@ -94,7 +94,6 @@ extern int scsi_eh_scmd_add(struct scsi_
extern int scsi_maybe_unblock_host(struct scsi_device *sdev);
extern void scsi_setup_cmd_retry(struct scsi_cmnd *cmd);
extern void scsi_device_unbusy(struct scsi_device *sdev);
-extern int scsi_queue_insert(struct scsi_cmnd *cmd, int reason);
extern void scsi_requeue_command(struct scsi_cmnd *cmd);
extern void scsi_next_command(struct scsi_cmnd *cmd);
extern void scsi_run_host_queues(struct Scsi_Host *shost);
^ permalink raw reply
* [PATCH scsi-misc-2.6 00/07] scsi: requeue path consolidation
From: Tejun Heo @ 2005-04-12 12:52 UTC (permalink / raw)
To: James.Bottomley, axboe, Christoph Hellwig; +Cc: linux-scsi, linux-kernel
Hello again, guys.
This is the last patchset and assumes that all previous patchsets are
applied. This patchset conolidates requeue paths such that all
requeue after command issue goes through scsi_requeue_command().
Requeueing due to unifinished bytes goes through
scsi_requeue_command_reprep() and due to error through
scsi_retry_command().
This is the last patchset before the new implementation of scsi
device state model. New state model is complete now and ready to be
splitted & submitted. As soon as these patchsets are settled, I'll
post the new device model patchset.
[ Start of patch descriptions ]
01_scsi_requeue_make_requeue_command_public.patch
: update and make public scsi_requeue_command()
This patch makes the following changes to
scsi_requeue_command() and make the function public.
* remove redundant argument @q
* remove REQ_DONTPREP clearing
* add state/owner setting
A new inline function scsi_requeue_command_reprep() is defined
and used for the original users of scsi_requeue_command().
Using a wrapper function for reprep cases is suggested by
Christoph Hellwig.
02_scsi_requeue_use_scsi_requeue_command_in_scsi_retry_command.patch
: make scsi_retry_command() use scsi_requeue_command()
scsi_retry_command() orignally used scsi_queue_insert() for
requeueing. This patch makes it use scsi_retry_command()
instead. Adding a call to scsi_device_unbusy() is sufficient
and the change also makes scsi_retry_command() symmetric with
scsi_finish_command() in how it unbusies the command. Also as
there's nothing to return, make the function void.
03_scsi_requeue_use_scsi_retry_command_instead_of_scsi_queue_insert.patch
: replace scsi_queue_insert() usages with scsi_retry_command()
There are two users of scsi_queue_insert() left now. One in
scsi_softirq() and the other in scsi_eh_flush_done_q(). The
only additional functionality of scsi_queue_insert() used is
setting device_blocked on ADD_TO_MLQUEUE case in
scsi_softirq().
Open code device_blocked setting and replace
scsi_queue_insert() with scsi_retry_command() in both cases.
04_scsi_requeue_remove_scsi_queue_insert.patch
: remove scsi_queue_insert()
scsi_queue_insert() now has no user left. Kill it.
05_scsi_requeue_move_init_cmd_errh.patch
: move scsi_init_cmd_errh() from request_fn to prep_fn.
As now all non-reprepped requeue goes through
scsi_retry_command() which clears sense buffer, there's no
need to call scsi_init_cmd_errh() in scsi_request_fn(). Move
scsi_init_cmd_errh() to scsi_prep_fn().
06_scsi_requeue_reset_result.patch
: add cmd->result clearing
cmd->result wasn't cleared on requeue or reprep. Clear it.
07_scsi_requeue_consolidate_setup_cmd_retry_calls_in_eh.patch
: consolidate scsi_cmd_retry() calls
scsi_setup_cmd_retry() is needed because scsi eh may alter
scsi_cmnd to issue eh commands. Consolidate calls to
scsi_setup_cmd_retry() to one place in scsi_eh_flush_done_q().
This change makes scsi_retry_command() more symmetrical with
scsi_finish_command().
[ End of patch descriptions ]
Thanks a lot.
^ permalink raw reply
* Re: [PATCH scsi-misc-2.6 02/07] scsi: make scsi_retry_command() use scsi_requeue_command()
From: Tejun Heo @ 2005-04-12 12:52 UTC (permalink / raw)
To: James.Bottomley, axboe, Christoph Hellwig; +Cc: linux-scsi, linux-kernel
In-Reply-To: <20050412125219.88E5C1F6@htj.dyndns.org>
02_scsi_requeue_use_scsi_requeue_command_in_scsi_retry_command.patch
scsi_retry_command() orignally used scsi_queue_insert() for
requeueing. This patch makes it use scsi_retry_command()
instead. Adding a call to scsi_device_unbusy() is sufficient
and the change also makes scsi_retry_command() symmetric with
scsi_finish_command() in how it unbusies the command. Also as
there's nothing to return, make the function void.
Signed-off-by: Tejun Heo <htejun@gmail.com>
scsi.c | 8 ++++++--
scsi_priv.h | 2 +-
2 files changed, 7 insertions(+), 3 deletions(-)
Index: scsi-reqfn-export/drivers/scsi/scsi.c
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi.c 2005-04-12 21:50:11.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi.c 2005-04-12 21:50:11.000000000 +0900
@@ -669,8 +669,12 @@ static void scsi_softirq(struct softirq_
* level drivers should not become re-entrant as a result of
* this.
*/
-int scsi_retry_command(struct scsi_cmnd *cmd)
+void scsi_retry_command(struct scsi_cmnd *cmd)
{
+ SCSI_LOG_MLQUEUE(1, printk("Retrying command %p\n", cmd));
+
+ scsi_device_unbusy(cmd->device);
+
/*
* Restore the SCSI command state.
*/
@@ -682,7 +686,7 @@ int scsi_retry_command(struct scsi_cmnd
*/
memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
- return scsi_queue_insert(cmd, SCSI_MLQUEUE_EH_RETRY);
+ scsi_requeue_command(cmd);
}
/*
Index: scsi-reqfn-export/drivers/scsi/scsi_priv.h
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi_priv.h 2005-04-12 21:50:11.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi_priv.h 2005-04-12 21:50:11.000000000 +0900
@@ -60,7 +60,7 @@ extern void scsi_exit_hosts(void);
extern int scsi_setup_command_freelist(struct Scsi_Host *shost);
extern void scsi_destroy_command_freelist(struct Scsi_Host *shost);
extern void scsi_done(struct scsi_cmnd *cmd);
-extern int scsi_retry_command(struct scsi_cmnd *cmd);
+extern void scsi_retry_command(struct scsi_cmnd *cmd);
extern int scsi_insert_special_req(struct scsi_request *sreq, int);
extern void scsi_init_cmd_from_req(struct scsi_cmnd *cmd,
struct scsi_request *sreq);
^ permalink raw reply
* Re: [PATCH scsi-misc-2.6 01/07] scsi: update and make public scsi_requeue_command()
From: Tejun Heo @ 2005-04-12 12:52 UTC (permalink / raw)
To: James.Bottomley, axboe, Christoph Hellwig; +Cc: linux-scsi, linux-kernel
In-Reply-To: <20050412125219.88E5C1F6@htj.dyndns.org>
01_scsi_requeue_make_requeue_command_public.patch
This patch makes the following changes to
scsi_requeue_command() and make the function public.
* remove redundant argument @q
* remove REQ_DONTPREP clearing
* add state/owner setting
A new inline function scsi_requeue_command_reprep() is defined
and used for the original users of scsi_requeue_command().
Using a wrapper function for reprep cases is suggested by
Christoph Hellwig.
Signed-off-by: Tejun Heo <htejun@gmail.com>
scsi_lib.c | 42 +++++++++++++++++++++++++-----------------
scsi_priv.h | 1 +
2 files changed, 26 insertions(+), 17 deletions(-)
Index: scsi-reqfn-export/drivers/scsi/scsi_lib.c
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi_lib.c 2005-04-12 21:50:11.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi_lib.c 2005-04-12 21:50:11.000000000 +0900
@@ -468,23 +468,24 @@ static void scsi_run_queue(struct reques
*
* Purpose: Handle post-processing of completed commands.
*
- * Arguments: q - queue to operate on
- * cmd - command that may need to be requeued.
+ * Arguments: cmd - command that need to be requeued.
*
* Returns: Nothing
*
- * Notes: After command completion, there may be blocks left
- * over which weren't finished by the previous command
- * this can be for a number of reasons - the main one is
- * I/O errors in the middle of the request, in which case
- * we need to request the blocks that come after the bad
- * sector.
+ * Notes: After command completion, a command may need to be
+ * requeued due to error or unfinished blocks. All
+ * requeueing after command issueing goes through this
+ * function. The caller is expected to have performed
+ * scsi_device_unbusy() before invoking this function.
*/
-static void scsi_requeue_command(struct request_queue *q, struct scsi_cmnd *cmd)
+void scsi_requeue_command(struct scsi_cmnd *cmd)
{
+ struct request_queue *q = cmd->device->request_queue;
unsigned long flags;
- cmd->request->flags &= ~REQ_DONTPREP;
+ cmd->state = SCSI_STATE_MLQUEUE;
+ cmd->owner = SCSI_OWNER_MIDLEVEL;
+
cmd->request->flags |= REQ_SOFTBARRIER;
spin_lock_irqsave(q->queue_lock, flags);
@@ -494,6 +495,12 @@ static void scsi_requeue_command(struct
scsi_run_queue(q);
}
+static inline void scsi_requeue_command_reprep(struct scsi_cmnd *cmd)
+{
+ cmd->request->flags &= ~REQ_DONTPREP;
+ scsi_requeue_command(cmd);
+}
+
void scsi_next_command(struct scsi_cmnd *cmd)
{
struct request_queue *q = cmd->device->request_queue;
@@ -558,7 +565,7 @@ static struct scsi_cmnd *scsi_end_reques
* leftovers in the front of the
* queue, and goose the queue again.
*/
- scsi_requeue_command(q, cmd);
+ scsi_requeue_command_reprep(cmd);
return cmd;
}
@@ -697,8 +704,9 @@ static void scsi_release_buffers(struct
* function will be goosed. If we are not done, then
* scsi_end_request will directly goose the queue.
*
- * b) We can just use scsi_requeue_command() here. This would
- * be used if we just wanted to retry, for example.
+ * b) We can just use scsi_requeue_command_reprep() here.
+ * This would be used if we just wanted to retry, for
+ * example.
*/
void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
unsigned int block_bytes)
@@ -820,7 +828,7 @@ void scsi_io_completion(struct scsi_cmnd
* media change, so we just retry the
* request and see what happens.
*/
- scsi_requeue_command(q, cmd);
+ scsi_requeue_command_reprep(cmd);
return;
}
break;
@@ -841,7 +849,7 @@ void scsi_io_completion(struct scsi_cmnd
* This will cause a retry with a 6-byte
* command.
*/
- scsi_requeue_command(q, cmd);
+ scsi_requeue_command_reprep(cmd);
result = 0;
} else {
cmd = scsi_end_request(cmd, 0, this_count, 1);
@@ -854,7 +862,7 @@ void scsi_io_completion(struct scsi_cmnd
* retry.
*/
if (sshdr.asc == 0x04 && sshdr.ascq == 0x01) {
- scsi_requeue_command(q, cmd);
+ scsi_requeue_command_reprep(cmd);
return;
}
printk(KERN_INFO "Device %s not ready.\n",
@@ -880,7 +888,7 @@ void scsi_io_completion(struct scsi_cmnd
* recovery reasons. Just retry the request
* and see what happens.
*/
- scsi_requeue_command(q, cmd);
+ scsi_requeue_command_reprep(cmd);
return;
}
if (result) {
Index: scsi-reqfn-export/drivers/scsi/scsi_priv.h
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi_priv.h 2005-04-12 21:50:11.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi_priv.h 2005-04-12 21:50:11.000000000 +0900
@@ -95,6 +95,7 @@ extern int scsi_maybe_unblock_host(struc
extern void scsi_setup_cmd_retry(struct scsi_cmnd *cmd);
extern void scsi_device_unbusy(struct scsi_device *sdev);
extern int scsi_queue_insert(struct scsi_cmnd *cmd, int reason);
+extern void scsi_requeue_command(struct scsi_cmnd *cmd);
extern void scsi_next_command(struct scsi_cmnd *cmd);
extern void scsi_run_host_queues(struct Scsi_Host *shost);
extern struct request_queue *scsi_alloc_queue(struct scsi_device *sdev);
^ permalink raw reply
* Re: [PATCH] drivers/scsi/sg.c: fix problems when sg_remove is called before sg_release
From: Douglas Gilbert @ 2005-04-12 11:03 UTC (permalink / raw)
To: Dailey, Nate; +Cc: 'linux-scsi@vger.kernel.org'
In-Reply-To: <92952AEF1F064042B6EF2522E0EEF437348251@EXNA.corp.stratus.com>
[-- Attachment #1: Type: text/plain, Size: 3022 bytes --]
Dailey, Nate wrote:
> This is my first attempt at submitting a patch, so I hope I'm not making any
> mistakes...
>
> This patch fixes two problems I came across in sg, both of which occur when
> sg_remove is called on a disk which hasn't yet been sg_release'd:
>
> 1. I got the following Oops in sg_remove:
>
> --
> Unable to handle kernel paging request at virtual address e0a58020
> printing eip:
> e0a7ceba
> *pde = 1c245c8b
> Oops: 0000 [#1]
> SMP
> CPU: 3
> EIP: 0060:[<e0a7ceba>] Tainted: G U
> EFLAGS: 00210246 (2.6.5-7.139-bigsmp )
> EIP is at sg_remove+0xba/0x240 [sg]
> eax: dfee0500 ebx: 00000000 ecx: dfeefa50 edx: dfee05a8
> esi: 00000000 edi: c7beb000 ebp: e0a58000 esp: daf4bec0
> ds: 007b es: 007b ss: 0068
> Process bash (pid: 27436, threadinfo=daf4a000 task=dbcd3350)
> Stack: c10c1840 000000d0 00000001 01500002 00000000 00200246 df844000
> e0a84d08
> df844240 e0857ec0 e0857f24 c0263dff e0857f0c df844240 df9d3028
> df9d3000
> fffffffa c0263e78 df844000 e08449be df9d3000 df844000 00000000
> fffffffa
> Call Trace:
> [<c0263dff>] class_device_del+0x5f/0xd0
> [<c0263e78>] class_device_unregister+0x8/0x10
> [<e08449be>] scsi_remove_device+0x3e/0xc0 [scsi_mod]
> [<e0845b59>] proc_scsi_write+0x269/0x2a0 [scsi_mod]
> [<c0176136>] vfs_write+0xc6/0x160
> [<c011057d>] do_mmap2+0xdd/0x170
> [<c01763e1>] sys_write+0x91/0xf0
> [<c0109199>] sysenter_past_esp+0x52/0x71
>
> Code: 8b 45 20 e8 ce 2a 70 df c7 45 20 00 00 00 00 8b 45 1c e8 ef
> --
>
> It looks like sg_remove needs to hold the sg_dev_arr_lock a little longer.
> After sg_remove dropped the lock, sg_release/sg_remove_sfp came along and
> freed the sdp... and then sg_remove tried to do cdev_del(sdp->cdev). I made
> a change to get what we need from the sdp while holding the lock, and it
> fixed the problem for me.
>
> 2. Scsi_device references are never released: after sg_remove sets the
> detached flag, sg_release won't call scsi_device_put. But someone needs to
> release the reference obtained in sg_open. A change also needs to be made in
> sg_remove_sfp to call scsi_device_put if freeing sdp--since sg_release
> wouldn't be able to do it in that case. I verified (by sticking a printk in
> scsi_device_dev_release) that the scsi_device wasn't freed in this case,
> without my change in place.
>
>
> To provoke these, I used a few 'dd if=/dev/sg2 of=/dev/null' commands to
> hold the device open. I then did 'echo "scsi remove-single-device 1 0 0 0" >
> /proc/scsi/scsi' to trigger the sg_remove.
>
> This patch is against 2.6.12-rc2, though I actually found/fixed the problems
> in 2.6.5-7.139 (SLES9 SP1).
>
> Do these look okay?
Nate,
Thanks for the analysis and the patch.
I'm starting to look at this patch and will do more
testing shortly. The changes look sound. The patch
had some line wrap problems so attached is my version
of it (against lk 2.6.12-rc2). It also applies over
my patch sent to this list on 28/3/2005 with a little
harmless "fuzz".
Doug Gilbert
[-- Attachment #2: sg2612rc2nd2.diff --]
[-- Type: text/x-patch, Size: 1707 bytes --]
--- linux/drivers/scsi/sg.c 2005-03-19 11:38:32.000000000 +1000
+++ linux/drivers/scsi/sg.c2612rc2nd2 2005-04-12 20:52:40.000000000 +1000
@@ -318,9 +318,7 @@
SCSI_LOG_TIMEOUT(3, printk("sg_release: %s\n", sdp->disk->disk_name));
sg_fasync(-1, filp, 0); /* remove filp from async notification list */
if (0 == sg_remove_sfp(sdp, sfp)) { /* Returns 1 when sdp gone */
- if (!sdp->detached) {
- scsi_device_put(sdp->device);
- }
+ scsi_device_put(sdp->device);
sdp->exclude = 0;
wake_up_interruptible(&sdp->o_excl_wait);
}
@@ -1574,19 +1572,29 @@
sg_nr_dev--;
break;
}
- write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
if (sdp) {
- sysfs_remove_link(&scsidp->sdev_gendev.kobj, "generic");
- class_simple_device_remove(MKDEV(SCSI_GENERIC_MAJOR, k));
- cdev_del(sdp->cdev);
+ struct cdev *tmp_cdev;
+ struct gendisk *tmp_disk;
+ int free_sdp = 0;
+
+ tmp_cdev = sdp->cdev;
sdp->cdev = NULL;
- devfs_remove("%s/generic", scsidp->devfs_name);
- put_disk(sdp->disk);
+ tmp_disk = sdp->disk;
sdp->disk = NULL;
if (NULL == sdp->headfp)
+ free_sdp = 1;
+ write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+
+ sysfs_remove_link(&scsidp->sdev_gendev.kobj, "generic");
+ class_simple_device_remove(MKDEV(SCSI_GENERIC_MAJOR, k));
+ cdev_del(tmp_cdev);
+ devfs_remove("%s/generic", scsidp->devfs_name);
+ put_disk(tmp_disk);
+ if (free_sdp)
kfree((char *) sdp);
- }
+ } else
+ write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
if (delay)
msleep(10); /* dirty detach so delay device destruction */
@@ -2550,6 +2558,7 @@
}
if (k < maxd)
sg_dev_arr[k] = NULL;
+ scsi_device_put(sdp->device);
kfree((char *) sdp);
res = 1;
}
^ permalink raw reply
* Re: [PATCH scsi-misc-2.6 00/04] scsi: scsi_request_fn() reimplementation
From: Tejun Heo @ 2005-04-12 11:01 UTC (permalink / raw)
To: Tejun Heo
Cc: James.Bottomley, axboe, Christoph Hellwig, linux-scsi,
linux-kernel
In-Reply-To: <20050412103128.69172FEB@htj.dyndns.org>
Tejun Heo wrote:
> Hello, guys.
>
> This patchset reimplements scsi_request_fn(). All prep's are moved
> into prep_fn and all state checking/issueing are moved into
> scsi_reqfn. prep_fn() only terminates/defers unpreparable requests
> and all requests are terminated through scsi midlayer.
>
This patchset assumes that previous patchsets 'timer updates' and
'clear REQ_SPECIAL/REQ_SOFTBARRIER usages' are applied.
Thanks.
--
tejun
^ permalink raw reply
* Re: [PATCH scsi-misc-2.6 03/04] scsi: make scsi_requeue_request() use blk_requeue_request()
From: Tejun Heo @ 2005-04-12 10:44 UTC (permalink / raw)
To: Christoph Hellwig, James.Bottomley, axboe, linux-scsi,
linux-kernel
In-Reply-To: <20050411124419.GA13747@infradead.org>
Hello, Christoph Hellwig.
On Mon, Apr 11, 2005 at 01:44:19PM +0100, Christoph Hellwig wrote:
> > + cmd->request->flags |= REQ_SOFTBARRIER;
> > +
> > + spin_lock_irqsave(q->queue_lock, flags);
> > + blk_requeue_request(q, cmd->request);
> > + spin_unlock_irqrestore(q->queue_lock, flags);
> >
> > scsi_run_queue(q);
>
> This exact code sequence is duplicated in the previous patch, maybe time
> for a
>
> void scsi_requeue_request(struct request *rq)
> {
> struct request_queue *q = rq->q;
> unsigned long flags;
>
> rq->flags |= REQ_SOFTBARRIER;
>
> spin_lock_irqsave(q->queue_lock, flags);
> blk_requeue_request(q, rq);
> spin_unlock_irqrestore(q->queue_lock, flags);
>
> scsi_run_queue(q);
> }
The duplicated code path is in scsi_queue_insert(), and the the
function is removed by later requeue path consolidation patchset. So,
I don't think separating out scsi_requeue_request() is necessary.
However, I'm thinking about setting REQ_SOFTBARRIER right after
allocating cmd in prep_fn(). So that we don't have to set
REQ_SOFTBARRIER in three different places. Also, IMHO, it better
represents the purpose of REQ_SOFTBARRIER.
Thanks a lot for your input. :-)
--
tejun
^ permalink raw reply
* Re: [PATCH scsi-misc-2.6 03/04] scsi: reimplement scsi_request_fn()
From: Tejun Heo @ 2005-04-12 10:37 UTC (permalink / raw)
To: James.Bottomley, axboe, Christoph Hellwig; +Cc: linux-scsi, linux-kernel
In-Reply-To: <20050412103128.5C5F0B72@htj.dyndns.org>
Oops, I forgot to mention that reqfn is reformatted mostly as
suggested by Chritoph Hellwig. Sorry.
On Tue, Apr 12, 2005 at 07:33:03PM +0900, Tejun Heo wrote:
> 03_scsi_reqfn_reimplementation.patch
>
> This patch rewrites scsi_request_fn(). scsi_dispatch_cmd() is
> merged into scsi_request_fn(). Goals are
>
> * Remove unnecessary operations (host_lock unlocking/locking,
> recursing into scsi_run_queue(), ...)
> * Consolidate defer/kill paths.
> * Be concise.
>
> The following bugs are fixed.
>
> * All killed requests now get fully prep'ed and pass through
> __scsi_done(). This is the only kill path.
> - scsi_cmnd leak in offline-kill path removed
> - unfinished request bug in
> scsi_dispatch_cmd():SDEV_DEL-kill path removed.
> - commands are never terminated directly from blk
> layer unless they are invalid, so no need to supply
> req->end_io callback for special requests.
> * Timer is added while holding host_lock, after all conditions
> are checked and serial number is assigned. This guarantees
> that until host_lock is released, the scsi_cmnd pointed to
> by cmd isn't released. That didn't hold in the original
> code and, theoretically, the original code could access
> already released cmd.
> * For the same reason, if shost->hostt->queuecommand() fails,
> we try to delete the timer before releasing host_lock.
>
> Other changes/notes
>
> * host_lock is acquired and released only once.
> enter (qlocked) -> enter loop -> dev-prep -> switch to hlock -\
> ^---- switch to qlock <- issue <- host-prep <-/
> * unnecessary if () on get_device() removed.
> * loop on elv_next_request() instead of blk_queue_plugged().
> We now explicitly break out of loop when we plug and check if
> the queue has been plugged underneath us at the end of loop.
> * All device/host state checks are done in this function and
> done only once while holding qlock/host_lock respectively.
> * Requests which get deferred during dev-prep are never
> removed from request queue, so deferring is achieved by
> simply breaking out of the loop and returning.
> * Failure of blk_queue_start_tag() on tagged queue is a BUG
> now. This condition should have been catched by
> scsi_dev_queue_ready().
> * req->special == NULL test removed. This just can't happen,
> and even if it ever happens, scsi_request_fn() will
> deterministically oops.
> * Requests which gets deferred during host-prep are requeued
> using blk_requeue_request(). This is the only requeue path.
>
> Note that scsi_kill_requests() still terminates requests using
> blk layer. The path is circular-ref workaround and soon to be
> replaced, so ignore it for now.
--
tejun
^ permalink raw reply
* Re: [PATCH scsi-misc-2.6 03/04] scsi: reimplement scsi_request_fn()
From: Tejun Heo @ 2005-04-12 10:33 UTC (permalink / raw)
To: James.Bottomley, axboe, Christoph Hellwig; +Cc: linux-scsi, linux-kernel
In-Reply-To: <20050412103128.69172FEB@htj.dyndns.org>
03_scsi_reqfn_reimplementation.patch
This patch rewrites scsi_request_fn(). scsi_dispatch_cmd() is
merged into scsi_request_fn(). Goals are
* Remove unnecessary operations (host_lock unlocking/locking,
recursing into scsi_run_queue(), ...)
* Consolidate defer/kill paths.
* Be concise.
The following bugs are fixed.
* All killed requests now get fully prep'ed and pass through
__scsi_done(). This is the only kill path.
- scsi_cmnd leak in offline-kill path removed
- unfinished request bug in
scsi_dispatch_cmd():SDEV_DEL-kill path removed.
- commands are never terminated directly from blk
layer unless they are invalid, so no need to supply
req->end_io callback for special requests.
* Timer is added while holding host_lock, after all conditions
are checked and serial number is assigned. This guarantees
that until host_lock is released, the scsi_cmnd pointed to
by cmd isn't released. That didn't hold in the original
code and, theoretically, the original code could access
already released cmd.
* For the same reason, if shost->hostt->queuecommand() fails,
we try to delete the timer before releasing host_lock.
Other changes/notes
* host_lock is acquired and released only once.
enter (qlocked) -> enter loop -> dev-prep -> switch to hlock -\
^---- switch to qlock <- issue <- host-prep <-/
* unnecessary if () on get_device() removed.
* loop on elv_next_request() instead of blk_queue_plugged().
We now explicitly break out of loop when we plug and check if
the queue has been plugged underneath us at the end of loop.
* All device/host state checks are done in this function and
done only once while holding qlock/host_lock respectively.
* Requests which get deferred during dev-prep are never
removed from request queue, so deferring is achieved by
simply breaking out of the loop and returning.
* Failure of blk_queue_start_tag() on tagged queue is a BUG
now. This condition should have been catched by
scsi_dev_queue_ready().
* req->special == NULL test removed. This just can't happen,
and even if it ever happens, scsi_request_fn() will
deterministically oops.
* Requests which gets deferred during host-prep are requeued
using blk_requeue_request(). This is the only requeue path.
Note that scsi_kill_requests() still terminates requests using
blk layer. The path is circular-ref workaround and soon to be
replaced, so ignore it for now.
Signed-off-by: Tejun Heo <htejun@gmail.com>
scsi.c | 137 ----------------------------
scsi_lib.c | 286 +++++++++++++++++++++++++++++++++---------------------------
scsi_priv.h | 1
3 files changed, 159 insertions(+), 265 deletions(-)
Index: scsi-reqfn-export/drivers/scsi/scsi.c
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi.c 2005-04-12 19:27:55.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi.c 2005-04-12 19:27:55.000000000 +0900
@@ -70,15 +70,6 @@
/*
- * Definitions and constants.
- */
-
-#define MIN_RESET_DELAY (2*HZ)
-
-/* Do not call reset on error if we just did a reset within 15 sec. */
-#define MIN_RESET_PERIOD (15*HZ)
-
-/*
* Note - the initial logging level can be set here to log events at boot time.
* After the system is up, you may enable logging via the /proc interface.
*/
@@ -495,134 +486,6 @@ void scsi_log_completion(struct scsi_cmn
}
#endif
-/*
- * Assign a serial number and pid to the request for error recovery
- * and debugging purposes. Protected by the Host_Lock of host.
- */
-static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd *cmd)
-{
- cmd->serial_number = host->cmd_serial_number++;
- if (cmd->serial_number == 0)
- cmd->serial_number = host->cmd_serial_number++;
-
- cmd->pid = host->cmd_pid++;
- if (cmd->pid == 0)
- cmd->pid = host->cmd_pid++;
-}
-
-/*
- * Function: scsi_dispatch_command
- *
- * Purpose: Dispatch a command to the low-level driver.
- *
- * Arguments: cmd - command block we are dispatching.
- *
- * Notes:
- */
-int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
-{
- struct Scsi_Host *host = cmd->device->host;
- unsigned long flags = 0;
- unsigned long timeout;
- int rtn = 0;
-
- /* check if the device is still usable */
- if (unlikely(cmd->device->sdev_state == SDEV_DEL)) {
- /* in SDEV_DEL we error all commands. DID_NO_CONNECT
- * returns an immediate error upwards, and signals
- * that the device is no longer present */
- cmd->result = DID_NO_CONNECT << 16;
- atomic_inc(&cmd->device->iorequest_cnt);
- scsi_done(cmd);
- /* return 0 (because the command has been processed) */
- goto out;
- }
-
- /* Check to see if the scsi lld put this device into state SDEV_BLOCK. */
- if (unlikely(cmd->device->sdev_state == SDEV_BLOCK)) {
- /*
- * in SDEV_BLOCK, the command is just put back on the device
- * queue. The suspend state has already blocked the queue so
- * future requests should not occur until the device
- * transitions out of the suspend state.
- */
- scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
-
- SCSI_LOG_MLQUEUE(3, printk("queuecommand : device blocked \n"));
-
- /*
- * NOTE: rtn is still zero here because we don't need the
- * queue to be plugged on return (it's already stopped)
- */
- goto out;
- }
-
- /*
- * We will wait MIN_RESET_DELAY clock ticks after the last reset so
- * we can avoid the drive not being ready.
- */
- timeout = host->last_reset + MIN_RESET_DELAY;
-
- if (host->resetting && time_before(jiffies, timeout)) {
- int ticks_remaining = timeout - jiffies;
- /*
- * NOTE: This may be executed from within an interrupt
- * handler! This is bad, but for now, it'll do. The irq
- * level of the interrupt handler has been masked out by the
- * platform dependent interrupt handling code already, so the
- * sti() here will not cause another call to the SCSI host's
- * interrupt handler (assuming there is one irq-level per
- * host).
- */
- while (--ticks_remaining >= 0)
- mdelay(1 + 999 / HZ);
- host->resetting = 0;
- }
-
- /*
- * AK: unlikely race here: for some reason the timer could
- * expire before the serial number is set up below.
- */
- scsi_add_timer(cmd, cmd->timeout_per_command);
-
- scsi_log_send(cmd);
-
- /*
- * We will use a queued command if possible, otherwise we will
- * emulate the queuing and calling of completion function ourselves.
- */
-
- cmd->state = SCSI_STATE_QUEUED;
- cmd->owner = SCSI_OWNER_LOWLEVEL;
-
- atomic_inc(&cmd->device->iorequest_cnt);
-
- spin_lock_irqsave(host->host_lock, flags);
- scsi_cmd_get_serial(host, cmd);
-
- if (unlikely(test_bit(SHOST_CANCEL, &host->shost_state))) {
- cmd->result = (DID_NO_CONNECT << 16);
- scsi_done(cmd);
- } else {
- rtn = host->hostt->queuecommand(cmd, scsi_done);
- }
- spin_unlock_irqrestore(host->host_lock, flags);
- if (rtn) {
- if (scsi_delete_timer(cmd)) {
- atomic_inc(&cmd->device->iodone_cnt);
- scsi_queue_insert(cmd,
- (rtn == SCSI_MLQUEUE_DEVICE_BUSY) ?
- rtn : SCSI_MLQUEUE_HOST_BUSY);
- }
- SCSI_LOG_MLQUEUE(3,
- printk("queuecommand : request rejected\n"));
- }
-
- out:
- SCSI_LOG_MLQUEUE(3, printk("leaving scsi_dispatch_cmnd()\n"));
- return rtn;
-}
-
/*
* Function: scsi_init_cmd_from_req
*
Index: scsi-reqfn-export/drivers/scsi/scsi_lib.c
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi_lib.c 2005-04-12 19:27:55.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi_lib.c 2005-04-12 19:27:55.000000000 +0900
@@ -28,6 +28,8 @@
#include "scsi_priv.h"
#include "scsi_logging.h"
+#define MIN_RESET_DELAY (2*HZ)
+
/*
* Macro to determine the size of SCSI command. This macro takes vendor
* unique commands into account. SCSI commands in groups 6 and 7 are
@@ -1036,32 +1038,6 @@ static int scsi_prep_fn(struct request_q
{
struct scsi_device *sdev = q->queuedata;
struct scsi_cmnd *cmd;
- int specials_only = 0;
-
- /*
- * Just check to see if the device is online. If it isn't, we
- * refuse to process any commands. The device must be brought
- * online before trying any recovery commands
- */
- if (unlikely(!scsi_device_online(sdev))) {
- printk(KERN_ERR "scsi%d (%d:%d): rejecting I/O to offline device\n",
- sdev->host->host_no, sdev->id, sdev->lun);
- return BLKPREP_KILL;
- }
- if (unlikely(sdev->sdev_state != SDEV_RUNNING)) {
- /* OK, we're not in a running state don't prep
- * user commands */
- if (sdev->sdev_state == SDEV_DEL) {
- /* Device is fully deleted, no commands
- * at all allowed down */
- printk(KERN_ERR "scsi%d (%d:%d): rejecting I/O to dead device\n",
- sdev->host->host_no, sdev->id, sdev->lun);
- return BLKPREP_KILL;
- }
- /* OK, we only allow special commands (i.e. not
- * user initiated ones */
- specials_only = sdev->sdev_state;
- }
/*
* Find the actual device driver associated with this command.
@@ -1084,30 +1060,12 @@ static int scsi_prep_fn(struct request_q
} else
cmd = req->special;
} else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
-
- if(unlikely(specials_only)) {
- if(specials_only == SDEV_QUIESCE ||
- specials_only == SDEV_BLOCK)
- return BLKPREP_DEFER;
-
- printk(KERN_ERR "scsi%d (%d:%d): rejecting I/O to device being removed\n",
- sdev->host->host_no, sdev->id, sdev->lun);
- return BLKPREP_KILL;
- }
-
-
- /*
- * Now try and find a command block that we can use.
- */
if (!req->special) {
cmd = scsi_get_command(sdev, GFP_ATOMIC);
if (unlikely(!cmd))
goto defer;
} else
cmd = req->special;
-
- /* pull a tag out of the request if we have one */
- cmd->tag = req->tag;
} else {
blk_dump_rq_flags(req, "SCSI bad req");
return BLKPREP_KILL;
@@ -1295,6 +1253,54 @@ static void scsi_kill_requests(request_q
}
/*
+ * scsi_wait_reset: We will wait MIN_RESET_DELAY clock ticks after the
+ * last reset so we can avoid the drive not being ready.
+ *
+ * Called with no lock held and irq disabled.
+ */
+static inline void scsi_wait_reset(struct Scsi_Host *shost)
+{
+ unsigned long timeout = shost->last_reset + MIN_RESET_DELAY;
+
+ if (shost->resetting && time_before(jiffies, timeout)) {
+ int ticks_remaining = timeout - jiffies;
+ /*
+ * NOTE: This may be executed from within an interrupt
+ * handler! This is bad, but for now, it'll do. The
+ * irq level of the interrupt handler has been masked
+ * out by the platform dependent interrupt handling
+ * code already, so the local_irq_enable() here will
+ * not cause another call to the SCSI host's interrupt
+ * handler (assuming there is one irq-level per host).
+ */
+ local_irq_enable();
+
+ while (--ticks_remaining >= 0)
+ mdelay(1 + 999 / HZ);
+ shost->resetting = 0;
+
+ local_irq_disable();
+ }
+}
+
+/*
+ * scsi_cmd_get_serial: Assign a serial number and pid to the request
+ * for error recovery and debugging purposes.
+ *
+ * Called with host_lock held.
+ */
+static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd *cmd)
+{
+ cmd->serial_number = host->cmd_serial_number++;
+ if (cmd->serial_number == 0)
+ cmd->serial_number = host->cmd_serial_number++;
+
+ cmd->pid = host->cmd_pid++;
+ if (cmd->pid == 0)
+ cmd->pid = host->cmd_pid++;
+}
+
+/*
* Function: scsi_request_fn()
*
* Purpose: Main strategy routine for SCSI.
@@ -1309,8 +1315,9 @@ static void scsi_request_fn(struct reque
{
struct scsi_device *sdev = q->queuedata;
struct Scsi_Host *shost;
- struct scsi_cmnd *cmd;
struct request *req;
+ struct scsi_cmnd *cmd;
+ int ret = 0;
if (!sdev) {
printk("scsi: killing requests for dead queue\n");
@@ -1318,117 +1325,142 @@ static void scsi_request_fn(struct reque
return;
}
- if(!get_device(&sdev->sdev_gendev))
- /* We must be tearing the block queue down already */
- return;
+ /* FIXME: Once fire & forgetters are fixed, this and the
+ * unlock_irq/put_device/lock_irq dance at the end of this
+ * function can go away. */
+ get_device(&sdev->sdev_gendev);
- /*
- * To start with, we keep looping until the queue is empty, or until
- * the host is no longer able to accept any more requests.
- */
shost = sdev->host;
- while (!blk_queue_plugged(q)) {
- int rtn;
- /*
- * get next queueable request. We do this early to make sure
- * that the request is fully prepared even if we cannot
- * accept it.
- */
- req = elv_next_request(q);
- if (!req || !scsi_dev_queue_ready(q, sdev))
- break;
-
- if (unlikely(!scsi_device_online(sdev))) {
- printk(KERN_ERR "scsi%d (%d:%d): rejecting I/O to offline device\n",
- sdev->host->host_no, sdev->id, sdev->lun);
- blkdev_dequeue_request(req);
- req->flags |= REQ_QUIET;
- while (end_that_request_first(req, 0, req->nr_sectors))
- ;
- end_that_request_last(req);
- continue;
- }
+ while ((req = elv_next_request(q))) {
+ enum scsi_device_state state;
+ int kill = 0, is_special = req->flags & REQ_SPECIAL;
+ cmd = req->special;
+ state = cmd->device->sdev_state;
- /*
- * Remove the request from the request list.
- */
- if (!(blk_queue_tagged(q) && !blk_queue_start_tag(q, req)))
+ if (state == SDEV_OFFLINE || state == SDEV_DEL ||
+ (state == SDEV_CANCEL && !is_special)) {
+ printk(KERN_ERR
+ "scsi%d (%d:%d): rejecting I/O to %s\n",
+ shost->host_no, sdev->id, sdev->lun,
+ (state == SDEV_OFFLINE ?
+ "offline device" :
+ (state == SDEV_DEL ?
+ "dead device" :
+ "device being removed")));
+ kill = 1;
+ } else if (state == SDEV_BLOCK ||
+ (state == SDEV_QUIESCE && !is_special) ||
+ !scsi_dev_queue_ready(q, sdev))
+ goto out;
+
+ /* Start tag / remove from the request queue. */
+ if (blk_queue_tagged(q)) {
+ if (blk_queue_start_tag(q, req))
+ BUG();
+ cmd->tag = req->tag;
+ } else
blkdev_dequeue_request(req);
+
sdev->device_busy++;
+ /* Switch to host_lock. */
spin_unlock(q->queue_lock);
+ scsi_wait_reset(shost);
spin_lock(shost->host_lock);
+ if (kill || test_bit(SHOST_CANCEL, &shost->shost_state)) {
+ SCSI_LOG_MLQUEUE(3,
+ printk("%s: rejecting request\n", __FUNCTION__));
+ shost->host_busy++;
+ atomic_inc(&sdev->iorequest_cnt);
+ cmd->result = DID_NO_CONNECT << 16;
+ __scsi_done(cmd);
+ goto relock;
+ }
+
if (!scsi_host_queue_ready(q, shost, sdev))
- goto not_ready;
+ goto requeue_out;
+
if (sdev->single_lun) {
- if (scsi_target(sdev)->starget_sdev_user &&
- scsi_target(sdev)->starget_sdev_user != sdev)
- goto not_ready;
- scsi_target(sdev)->starget_sdev_user = sdev;
+ struct scsi_target *target = scsi_target(sdev);
+ if (target->starget_sdev_user &&
+ target->starget_sdev_user != sdev)
+ goto requeue_out;
+ target->starget_sdev_user = sdev;
}
+
+ /* Once requeue path is cleaned up, init_cmd_errh can
+ * be moved to prep_fn() where it belongs. */
+ scsi_init_cmd_errh(cmd);
shost->host_busy++;
+ scsi_log_send(cmd);
+ scsi_cmd_get_serial(shost, cmd);
+ scsi_add_timer(cmd, cmd->timeout_per_command);
- /*
- * XXX(hch): This is rather suboptimal, scsi_dispatch_cmd will
- * take the lock again.
- */
- spin_unlock_irq(shost->host_lock);
+ cmd->state = SCSI_STATE_QUEUED;
+ cmd->owner = SCSI_OWNER_LOWLEVEL;
- cmd = req->special;
- if (unlikely(cmd == NULL)) {
- printk(KERN_CRIT "impossible request in %s.\n"
- "please mail a stack trace to "
- "linux-scsi@vger.kernel.org",
- __FUNCTION__);
- BUG();
+ ret = shost->hostt->queuecommand(cmd, scsi_done);
+ if (ret) {
+ SCSI_LOG_MLQUEUE(3,
+ printk("%s: queuecommand deferred request (%d)\n",
+ __FUNCTION__, ret));
+ /*
+ * Timer should be deleted while holding the
+ * host_lock. Once it gets released, we don't
+ * know if cmd is still there or not.
+ */
+ if (scsi_delete_timer(cmd)) {
+ shost->host_busy--;
+ goto block_requeue_out;
+ }
+
+ spin_unlock_irq(shost->host_lock);
+ goto out_unlocked;
}
- /*
- * Finally, initialize any error handling parameters, and set up
- * the timers for timeouts.
- */
- scsi_init_cmd_errh(cmd);
+ atomic_inc(&sdev->iorequest_cnt);
- /*
- * Dispatch the command to the low-level driver.
- */
- rtn = scsi_dispatch_cmd(cmd);
- spin_lock_irq(q->queue_lock);
- if(rtn) {
- /* we're refusing the command; because of
- * the way locks get dropped, we need to
- * check here if plugging is required */
- if(sdev->device_busy == 0)
- blk_plug_device(q);
+ relock:
+ /* Switch back to queue_lock. */
+ spin_unlock(shost->host_lock);
+ spin_lock(q->queue_lock);
- break;
- }
+ /* The queue could have been plugged underneath us. */
+ if (blk_queue_plugged(q))
+ goto out;
}
goto out;
- not_ready:
- spin_unlock_irq(shost->host_lock);
+ block_requeue_out:
+ if (ret == SCSI_MLQUEUE_DEVICE_BUSY)
+ sdev->device_blocked = sdev->max_device_blocked;
+ else
+ shost->host_blocked = shost->max_host_blocked;
+ requeue_out:
+ /* Switch back to queue_lock */
+ spin_unlock(shost->host_lock);
+ spin_lock(q->queue_lock);
- /*
- * lock q, handle tag, requeue req, and decrement device_busy. We
- * must return with queue_lock held.
- *
- * Decrementing device_busy without checking it is OK, as all such
- * cases (host limits or settings) should run the queue at some
- * later time.
- */
- spin_lock_irq(q->queue_lock);
+ cmd->state = SCSI_STATE_MLQUEUE;
+ cmd->owner = SCSI_OWNER_MIDLEVEL;
+
+ SCSI_LOG_MLQUEUE(3,
+ printk("%s: requeueing request\n", __FUNCTION__));
+
+ req->flags |= REQ_SOFTBARRIER; /* Don't pass this request. */
blk_requeue_request(q, req);
- sdev->device_busy--;
- if(sdev->device_busy == 0)
+ if (--sdev->device_busy == 0)
blk_plug_device(q);
out:
- /* must be careful here...if we trigger the ->remove() function
- * we cannot be holding the q lock */
+ /*
+ * must be careful here...if we trigger the ->remove() function
+ * we cannot be holding the q lock
+ */
spin_unlock_irq(q->queue_lock);
+ out_unlocked:
put_device(&sdev->sdev_gendev);
spin_lock_irq(q->queue_lock);
}
Index: scsi-reqfn-export/drivers/scsi/scsi_priv.h
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi_priv.h 2005-04-12 19:27:54.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi_priv.h 2005-04-12 19:27:55.000000000 +0900
@@ -57,7 +57,6 @@ extern int scsi_init_hosts(void);
extern void scsi_exit_hosts(void);
/* scsi.c */
-extern int scsi_dispatch_cmd(struct scsi_cmnd *cmd);
extern int scsi_setup_command_freelist(struct Scsi_Host *shost);
extern void scsi_destroy_command_freelist(struct Scsi_Host *shost);
extern void scsi_done(struct scsi_cmnd *cmd);
^ permalink raw reply
* Re: [PATCH scsi-misc-2.6 04/04] scsi: remove unnecessary scsi_wait_req_end_io()
From: Tejun Heo @ 2005-04-12 10:33 UTC (permalink / raw)
To: James.Bottomley, axboe, Christoph Hellwig; +Cc: linux-scsi, linux-kernel
In-Reply-To: <20050412103128.69172FEB@htj.dyndns.org>
04_scsi_reqfn_remove_wait_req_end_io.patch
As all requests are now terminated via scsi midlayer, we don't
need to set end_io for special reqs, remove it.
Note that scsi_kill_requests() still terminates requests using
blk layer. The path is circular-ref workaround and soon to be
replaced, so ignore it for now.
Signed-off-by: Tejun Heo <htejun@gmail.com>
scsi_lib.c | 11 -----------
1 files changed, 11 deletions(-)
Index: scsi-reqfn-export/drivers/scsi/scsi_lib.c
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi_lib.c 2005-04-12 19:27:55.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi_lib.c 2005-04-12 19:27:56.000000000 +0900
@@ -260,16 +260,6 @@ static void scsi_wait_done(struct scsi_c
complete(req->waiting);
}
-/* This is the end routine we get to if a command was never attached
- * to the request. Simply complete the request without changing
- * rq_status; this will cause a DRIVER_ERROR. */
-static void scsi_wait_req_end_io(struct request *req)
-{
- BUG_ON(!req->waiting);
-
- complete(req->waiting);
-}
-
void scsi_wait_req(struct scsi_request *sreq, const void *cmnd, void *buffer,
unsigned bufflen, int timeout, int retries)
{
@@ -277,7 +267,6 @@ void scsi_wait_req(struct scsi_request *
sreq->sr_request->waiting = &wait;
sreq->sr_request->rq_status = RQ_SCSI_BUSY;
- sreq->sr_request->end_io = scsi_wait_req_end_io;
scsi_do_req(sreq, cmnd, buffer, bufflen, scsi_wait_done,
timeout, retries);
wait_for_completion(&wait);
^ permalink raw reply
* Re: [PATCH scsi-misc-2.6 02/04] scsi: move request preps in other places into prep_fn()
From: Tejun Heo @ 2005-04-12 10:32 UTC (permalink / raw)
To: James.Bottomley, axboe, Christoph Hellwig; +Cc: linux-scsi, linux-kernel
In-Reply-To: <20050412103128.69172FEB@htj.dyndns.org>
02_scsi_reqfn_move_preps_to_prep_fn.patch
Move request preparations scattered in scsi_request_fn() and
scsi_dispatch_cmd() into scsi_prep_fn()
* CDB_SIZE check in scsi_dispatch_cmd()
* SCSI-2 LUN preparation in scsi_dispatch_cmd()
No invalid request reaches scsi_request_fn() anymore.
Note that scsi_init_cmd_errh() is still left in
scsi_request_fn(). As all requeued requests need its sense
buffer and result value cleared, we can't move this to
prep_fn() yet. This is moved into prep_fn in the following
requeue path consoildation patchset.
Signed-off-by: Tejun Heo <htejun@gmail.com>
scsi.c | 30 ------------------------------
scsi_lib.c | 17 +++++++++++++++++
2 files changed, 17 insertions(+), 30 deletions(-)
Index: scsi-reqfn-export/drivers/scsi/scsi.c
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi.c 2005-04-12 19:27:54.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi.c 2005-04-12 19:27:55.000000000 +0900
@@ -79,15 +79,6 @@
#define MIN_RESET_PERIOD (15*HZ)
/*
- * Macro to determine the size of SCSI command. This macro takes vendor
- * unique commands into account. SCSI commands in groups 6 and 7 are
- * vendor unique and we will depend upon the command length being
- * supplied correctly in cmd_len.
- */
-#define CDB_SIZE(cmd) (((((cmd)->cmnd[0] >> 5) & 7) < 6) ? \
- COMMAND_SIZE((cmd)->cmnd[0]) : (cmd)->cmd_len)
-
-/*
* Note - the initial logging level can be set here to log events at boot time.
* After the system is up, you may enable logging via the /proc interface.
*/
@@ -566,14 +557,6 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
goto out;
}
- /*
- * If SCSI-2 or lower, store the LUN value in cmnd.
- */
- if (cmd->device->scsi_level <= SCSI_2) {
- cmd->cmnd[1] = (cmd->cmnd[1] & 0x1f) |
- (cmd->device->lun << 5 & 0xe0);
- }
-
/*
* We will wait MIN_RESET_DELAY clock ticks after the last reset so
* we can avoid the drive not being ready.
@@ -614,19 +597,6 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
atomic_inc(&cmd->device->iorequest_cnt);
- /*
- * Before we queue this command, check if the command
- * length exceeds what the host adapter can handle.
- */
- if (CDB_SIZE(cmd) > cmd->device->host->max_cmd_len) {
- SCSI_LOG_MLQUEUE(3,
- printk("queuecommand : command too long.\n"));
- cmd->result = (DID_ABORT << 16);
-
- scsi_done(cmd);
- goto out;
- }
-
spin_lock_irqsave(host->host_lock, flags);
scsi_cmd_get_serial(host, cmd);
Index: scsi-reqfn-export/drivers/scsi/scsi_lib.c
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi_lib.c 2005-04-12 19:27:55.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi_lib.c 2005-04-12 19:27:55.000000000 +0900
@@ -28,6 +28,14 @@
#include "scsi_priv.h"
#include "scsi_logging.h"
+/*
+ * Macro to determine the size of SCSI command. This macro takes vendor
+ * unique commands into account. SCSI commands in groups 6 and 7 are
+ * vendor unique and we will depend upon the command length being
+ * supplied correctly in cmd_len.
+ */
+#define CDB_SIZE(cmd) (((((cmd)->cmnd[0] >> 5) & 7) < 6) ? \
+ COMMAND_SIZE((cmd)->cmnd[0]) : (cmd)->cmd_len)
#define SG_MEMPOOL_NR (sizeof(scsi_sg_pools)/sizeof(struct scsi_host_sg_pool))
#define SG_MEMPOOL_SIZE 32
@@ -1160,6 +1168,15 @@ static int scsi_prep_fn(struct request_q
goto kill;
}
+ /* Check command length. */
+ if (CDB_SIZE(cmd) > sdev->host->max_cmd_len)
+ goto kill;
+
+ /* If SCSI-2 or lower, store the LUN value in cmnd. */
+ if (cmd->device->scsi_level <= SCSI_2)
+ cmd->cmnd[1] = (cmd->cmnd[1] & 0x1f) |
+ (cmd->device->lun << 5 & 0xe0);
+
/*
* The request is now prepped, no need to come back here
*/
^ permalink raw reply
* [PATCH scsi-misc-2.6 00/04] scsi: scsi_request_fn() reimplementation
From: Tejun Heo @ 2005-04-12 10:32 UTC (permalink / raw)
To: James.Bottomley, axboe, Christoph Hellwig; +Cc: linux-scsi, linux-kernel
Hello, guys.
This patchset reimplements scsi_request_fn(). All prep's are moved
into prep_fn and all state checking/issueing are moved into
scsi_reqfn. prep_fn() only terminates/defers unpreparable requests
and all requests are terminated through scsi midlayer.
[ Start of patch descriptions ]
01_scsi_reqfn_consolidate_error_handling.patch
: consolidate error handling out of scsi_init_io() into scsi_prep_fn()
This patch fixes a queue stall bug which occurred when sgtable
allocation failed and device_busy == 0. When scsi_init_io()
returns BLKPREP_DEFER or BLKPREP_KILL, it's supposed to free
resources itself. This patch consolidates defer and kill
handling into scsi_prep_fn().
Note that this patch doesn't consolidate state defer/kill
handlings in scsi_prep_fn(). They were omitted as all state
checks will be moved into scsi_reques_fn() by the following
reqfn_reimpl patch.
ret value checking was changed to switch() as in James's
patch. Also, kill: comment is copied from James's patch.
02_scsi_reqfn_move_preps_to_prep_fn.patch
: move request preps in other places into prep_fn()
Move request preparations scattered in scsi_request_fn() and
scsi_dispatch_cmd() into scsi_prep_fn()
* CDB_SIZE check in scsi_dispatch_cmd()
* SCSI-2 LUN preparation in scsi_dispatch_cmd()
No invalid request reaches scsi_request_fn() anymore.
Note that scsi_init_cmd_errh() is still left in
scsi_request_fn(). As all requeued requests need its sense
buffer and result value cleared, we can't move this to
prep_fn() yet. This is moved into prep_fn in the following
requeue path consoildation patchset.
03_scsi_reqfn_reimplementation.patch
: reimplement scsi_request_fn()
This patch rewrites scsi_request_fn(). scsi_dispatch_cmd() is
merged into scsi_request_fn(). Goals are
* Remove unnecessary operations (host_lock unlocking/locking,
recursing into scsi_run_queue(), ...)
* Consolidate defer/kill paths.
* Be concise.
The following bugs are fixed.
* All killed requests now get fully prep'ed and pass through
__scsi_done(). This is the only kill path.
- scsi_cmnd leak in offline-kill path removed
- unfinished request bug in
scsi_dispatch_cmd():SDEV_DEL-kill path removed.
- commands are never terminated directly from blk
layer unless they are invalid, so no need to supply
req->end_io callback for special requests.
* Timer is added while holding host_lock, after all conditions
are checked and serial number is assigned. This guarantees
that until host_lock is released, the scsi_cmnd pointed to
by cmd isn't released. That didn't hold in the original
code and, theoretically, the original code could access
already released cmd.
* For the same reason, if shost->hostt->queuecommand() fails,
we try to delete the timer before releasing host_lock.
Other changes/notes
* host_lock is acquired and released only once.
enter (qlocked) -> enter loop -> dev-prep -> switch to hlock -\
^---- switch to qlock <- issue <- host-prep <-/
* unnecessary if () on get_device() removed.
* loop on elv_next_request() instead of blk_queue_plugged().
We now explicitly break out of loop when we plug and check if
the queue has been plugged underneath us at the end of loop.
* All device/host state checks are done in this function and
done only once while holding qlock/host_lock respectively.
* Requests which get deferred during dev-prep are never
removed from request queue, so deferring is achieved by
simply breaking out of the loop and returning.
* Failure of blk_queue_start_tag() on tagged queue is a BUG
now. This condition should have been catched by
scsi_dev_queue_ready().
* req->special == NULL test removed. This just can't happen,
and even if it ever happens, scsi_request_fn() will
deterministically oops.
* Requests which gets deferred during host-prep are requeued
using blk_requeue_request(). This is the only requeue path.
Note that scsi_kill_requests() still terminates requests using
blk layer. The path is circular-ref workaround and soon to be
replaced, so ignore it for now.
04_scsi_reqfn_remove_wait_req_end_io.patch
: remove unnecessary scsi_wait_req_end_io()
As all requests are now terminated via scsi midlayer, we don't
need to set end_io for special reqs, remove it.
Note that scsi_kill_requests() still terminates requests using
blk layer. The path is circular-ref workaround and soon to be
replaced, so ignore it for now.
[ End of patch descriptions ]
Thanks a lot.
^ permalink raw reply
* Re: [PATCH scsi-misc-2.6 01/04] scsi: consolidate error handling out of scsi_init_io() into scsi_prep_fn()
From: Tejun Heo @ 2005-04-12 10:32 UTC (permalink / raw)
To: James.Bottomley, axboe, Christoph Hellwig; +Cc: linux-scsi, linux-kernel
In-Reply-To: <20050412103128.69172FEB@htj.dyndns.org>
01_scsi_reqfn_consolidate_error_handling.patch
This patch fixes a queue stall bug which occurred when sgtable
allocation failed and device_busy == 0. When scsi_init_io()
returns BLKPREP_DEFER or BLKPREP_KILL, it's supposed to free
resources itself. This patch consolidates defer and kill
handling into scsi_prep_fn().
Note that this patch doesn't consolidate state defer/kill
handlings in scsi_prep_fn(). They were omitted as all state
checks will be moved into scsi_reques_fn() by the following
reqfn_reimpl patch.
ret value checking was changed to switch() as in James's
patch. Also, kill: comment is copied from James's patch.
Signed-off-by: Tejun Heo <htejun@gmail.com>
scsi_lib.c | 46 +++++++++++++++++++++++++++++++---------------
1 files changed, 31 insertions(+), 15 deletions(-)
Index: scsi-reqfn-export/drivers/scsi/scsi_lib.c
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi_lib.c 2005-04-12 19:27:55.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi_lib.c 2005-04-12 19:27:55.000000000 +0900
@@ -945,10 +945,8 @@ static int scsi_init_io(struct scsi_cmnd
* if sg table allocation fails, requeue request later.
*/
sgpnt = scsi_alloc_sgtable(cmd, GFP_ATOMIC);
- if (unlikely(!sgpnt)) {
- req->flags |= REQ_SOFTBARRIER;
+ if (unlikely(!sgpnt))
return BLKPREP_DEFER;
- }
cmd->request_buffer = (char *) sgpnt;
cmd->request_bufflen = req->nr_sectors << 9;
@@ -975,9 +973,6 @@ static int scsi_init_io(struct scsi_cmnd
printk(KERN_ERR "req nr_sec %lu, cur_nr_sec %u\n", req->nr_sectors,
req->current_nr_sectors);
- /* release the command and kill it */
- scsi_release_buffers(cmd);
- scsi_put_command(cmd);
return BLKPREP_KILL;
}
@@ -1145,18 +1140,24 @@ static int scsi_prep_fn(struct request_q
* required).
*/
ret = scsi_init_io(cmd);
- if (ret) /* BLKPREP_KILL return also releases the command */
- return ret;
+ switch (ret) {
+ case 0:
+ /* Successful initialization. */
+ break;
+ case BLKPREP_DEFER:
+ goto defer;
+ default:
+ /* Unknown return value, fall through. */
+ case BLKPREP_KILL:
+ goto kill;
+ }
/*
* Initialize the actual SCSI command for this request.
*/
drv = *(struct scsi_driver **)req->rq_disk->private_data;
- if (unlikely(!drv->init_command(cmd))) {
- scsi_release_buffers(cmd);
- scsi_put_command(cmd);
- return BLKPREP_KILL;
- }
+ if (unlikely(!drv->init_command(cmd)))
+ goto kill;
}
/*
@@ -1166,12 +1167,27 @@ static int scsi_prep_fn(struct request_q
return BLKPREP_OK;
defer:
- /* If we defer, the elv_next_request() returns NULL, but the
+ /*
+ * If we defer, the elv_next_request() returns NULL, but the
* queue must be restarted, so we plug here if no returning
- * command will automatically do that. */
+ * command will automatically do that. Also, the request may
+ * have its cmd allocated, so we set REQ_SOFTBARRIER.
+ */
if (sdev->device_busy == 0)
blk_plug_device(q);
+ req->flags |= REQ_SOFTBARRIER;
return BLKPREP_DEFER;
+
+ kill:
+ /*
+ * Here we have to release every resource associated with the
+ * request because this will complete at the request level
+ * (req->end_io), not the scsi command level, so no scsi
+ * routine will get to free the associated resources.
+ */
+ scsi_release_buffers(cmd);
+ scsi_put_command(cmd);
+ return BLKPREP_KILL;
}
/*
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox