public inbox for linux-scsi@vger.kernel.org
 help / color / mirror / Atom feed
From: Jens Axboe <axboe@suse.de>
To: Kai Makisara <Kai.Makisara@kolumbus.fi>
Cc: Joachim Feise <jfeise@ics.uci.edu>,
	linux-scsi@vger.kernel.org, Michael Guntsche <mike@it-loops.com>,
	Andrew Morton <akpm@osdl.org>,
	"Justin T. Gibbs" <gibbs@scsiguy.com>,
	Frank Pieczynski <pieczy@web.de>
Subject: Re: PROBLEM: 2.6.3 hangs when writing to scsi-dvd
Date: Mon, 23 Feb 2004 14:26:34 +0100	[thread overview]
Message-ID: <20040223132634.GD32010@suse.de> (raw)
In-Reply-To: <Pine.LNX.4.58.0402231329480.1749@kai.makisara.local>

On Mon, Feb 23 2004, Kai Makisara wrote:
> Please trim the cc list as appropriate. I am including all of the people 
> from the various messages related to probably one problem to get all of us 
> on the same track. Jens is included because he might directly see a 
> solution.
> 
> On Fri, 20 Feb 2004, Joachim Feise wrote:
> 
> > Joachim Feise wrote on 2/19/2004 11:47:
> > 
> > > [1.] One line summary of the problem:
> > > 2.6.3 hangs when writing to scsi-dvd
> > > 
> > > [2.] Full description of the problem/report:
> > > 
> > > I have a DVD drive (BTC1004) connected via an IDE-SCSI bridge to
> > > an Adaptec 29160 host adapter.
> > > With kernel 2.6.3, I experience a complete system hang whenever I try
> > > to record data on a DVD.
> > > It requires a reboot.
> > 
> > More info:
> > on the cdwrite list, somebody reported a similar problem
> > (http://lists.debian.org/cdwrite/2004/cdwrite-200402/msg00081.html)
> > 
> > His quick-n-dirty fix works for me:
> > 
> > --- linux-2.6.3/drivers/scsi/scsi_lib.c.orig    2004-02-17 19:57:57.000000000 -0800
> > +++ linux-2.6.3/drivers/scsi/scsi_lib.c 2004-02-20 13:52:46.000000000 -0800
> > @@ -1292,7 +1292,7 @@
> >          * host adapters.  A host driver can alter this mask in its
> >          * slave_alloc() or slave_configure() callback if necessary.
> >          */
> > -       blk_queue_dma_alignment(q, (8 - 1));
> > +       /* blk_queue_dma_alignment(q, (8 - 1)); */
> > 
> >         if (!shost->use_clustering)
> >                 clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
> > 
> > But without knowing what this particular line does, it is impossible for me
> > to say if commenting out the line is the right thing to do.
> > 
> This line has has several duties. For me, it sets the alignment constaint 
> used by st for deciding whether to use direct i/o or internal buffer. For 
> other people more important is that it is used for similar purpose in 
> linux/fs/bio.c. The beginning of __bio_map_user contains the following:
> 
>         /*
>          * transfer and buffer must be aligned to at least hardsector
>          * size for now, in the future we can relax this restriction
>          */
>         if ((uaddr & queue_dma_alignment(q)) || (len & queue_dma_alignment(q)))
>                 return NULL;
> 
> Without the call to blk_queue_alignment() in scsi_lib.c, the queue 
> alignment is to 512 byte boundary and the transfer size must be a multiple 
> of 512 bytes. With the calls, the unit is 8 bytes.
> 
> The function sg_io in linux/drivers/scsi/scsi_ioctl.c contains this:
> 
>                 /*
>                  * first try to map it into a bio. reading from device will
>                  * be a write to vm.
>                  */
>                 bio = bio_map_user(q, NULL, (unsigned long) hdr->dxferp,
>                                    hdr->dxfer_len, reading);
> 
>                 /*
>                  * if bio setup failed, fall back to slow approach
>                  */
>                 if (!bio) {
> 
> bio_map_user() calls __bio_map_user() and so the previous conditions are 
> used in sg_io() to decide on bouncing.
> 
> I made a test program that uses sg_io() to send a command to a SCSI 
> device. I tested it with a SCSI tape device. Without any changes the 
> program hung. The SCSI driver was sym53c8xx_2 and it loops on the 
> following error:
> 
> Feb 23 13:24:17 box kernel: sym1:5:0:extraneous data discarded.
> Feb 23 13:24:17 box kernel: sym1:5:0:COMMAND FAILED (87 0 1).
> Feb 23 13:24:17 box kernel: SCSI error : <1 0 5 0> return code = 0x70000
> 
> The I modified the program to align the buffer to 512 byte boundary. This 
> did not help. The next step was to set the transfer size to 512 bytes. 
> This helps!! Restoring the non-512 byte alignment did not cause any 
> problems.
> 
> The conclusion at this phase is that _the tranfer length in bio must be a 
> multiple of 512 bytes_.
> 
> I hope someone sees no where the real problem is.

SCSI io completion path (sr/sd/st rw_intr() -> scsi_io_completion() ->
scsi_end_request()) doesn't properly handle non-sector aligned data
transfers. This patch should fix it up. Warning: untested.

===== drivers/scsi/scsi_lib.c 1.118 vs edited =====
--- 1.118/drivers/scsi/scsi_lib.c	Mon Feb  2 17:14:22 2004
+++ edited/drivers/scsi/scsi_lib.c	Mon Feb 23 14:21:36 2004
@@ -493,7 +493,7 @@
  *		at some point during this call.
  */
 static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate,
-					  int sectors, int requeue)
+					  int bytes, int requeue)
 {
 	request_queue_t *q = cmd->device->request_queue;
 	struct request *req = cmd->request;
@@ -503,12 +503,15 @@
 	 * If there are blocks left over at the end, set up the command
 	 * to queue the remainder of them.
 	 */
-	if (end_that_request_first(req, uptodate, sectors)) {
-		int leftover = req->hard_nr_sectors - sectors;
+	if (end_that_request_chunk(req, uptodate, bytes)) {
+		int leftover = (req->hard_nr_sectors << 9) - bytes;
+
+		if (blk_pc_request(req))
+			leftover = req->data_len - bytes;
 
 		/* kill remainder if no retrys */
 		if (!uptodate && blk_noretry_request(req))
-			end_that_request_first(req, 0, leftover);
+			end_that_request_chunk(req, 0, leftover);
 		else {
 			if (requeue)
 				/*
@@ -649,11 +652,11 @@
  *		b) We can just use scsi_requeue_command() here.  This would
  *		   be used if we just wanted to retry, for example.
  */
-void scsi_io_completion(struct scsi_cmnd *cmd, int good_sectors,
-			int block_sectors)
+void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
+			unsigned int block_bytes)
 {
 	int result = cmd->result;
-	int this_count = cmd->bufflen >> 9;
+	int this_count = cmd->bufflen;
 	request_queue_t *q = cmd->device->request_queue;
 	struct request *req = cmd->request;
 	int clear_errors = 1;
@@ -705,9 +708,9 @@
 	 * Next deal with any sectors which we were able to correctly
 	 * handle.
 	 */
-	if (good_sectors >= 0) {
-		SCSI_LOG_HLCOMPLETE(1, printk("%ld sectors total, %d sectors done.\n",
-					      req->nr_sectors, good_sectors));
+	if (good_bytes >= 0) {
+		SCSI_LOG_HLCOMPLETE(1, printk("%ld sectors total, %d bytes done.\n",
+					      req->nr_sectors, good_bytes));
 		SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n", cmd->use_sg));
 
 		if (clear_errors)
@@ -717,13 +720,13 @@
 		 * they will have been finished off by the first command.
 		 * If not, then we have a multi-buffer command.
 		 *
-		 * If block_sectors != 0, it means we had a medium error
+		 * If block_bytes != 0, it means we had a medium error
 		 * of some sort, and that we want to mark some number of
 		 * sectors as not uptodate.  Thus we want to inhibit
 		 * requeueing right here - we will requeue down below
 		 * when we handle the bad sectors.
 		 */
-		cmd = scsi_end_request(cmd, 1, good_sectors, result == 0);
+		cmd = scsi_end_request(cmd, 1, good_bytes, result == 0);
 
 		/*
 		 * If the command completed without error, then either finish off the
@@ -808,7 +811,7 @@
 			       (int) cmd->device->id, (int) cmd->device->lun);
 			print_command(cmd->data_cmnd);
 			print_sense("", cmd);
-			cmd = scsi_end_request(cmd, 0, block_sectors, 1);
+			cmd = scsi_end_request(cmd, 0, block_bytes, 1);
 			return;
 		default:
 			break;
@@ -837,8 +840,10 @@
 		 * We sometimes get this cruft in the event that a medium error
 		 * isn't properly reported.
 		 */
-		cmd = scsi_end_request(cmd, 0, req->current_nr_sectors, 1);
-		return;
+		block_bytes = req->hard_cur_sectors << 9;
+		if (!block_bytes)
+			block_bytes = req->data_len;
+		cmd = scsi_end_request(cmd, 0, block_bytes, 1);
 	}
 }
 
===== drivers/scsi/sd.c 1.140 vs edited =====
--- 1.140/drivers/scsi/sd.c	Wed Feb  4 20:20:06 2004
+++ edited/drivers/scsi/sd.c	Mon Feb 23 14:10:00 2004
@@ -661,8 +661,8 @@
 static void sd_rw_intr(struct scsi_cmnd * SCpnt)
 {
 	int result = SCpnt->result;
-	int this_count = SCpnt->bufflen >> 9;
-	int good_sectors = (result == 0 ? this_count : 0);
+	int this_count = SCpnt->bufflen;
+	int good_bytes = (result == 0 ? this_count : 0);
 	sector_t block_sectors = 1;
 	sector_t error_sector;
 #ifdef CONFIG_SCSI_LOGGING
@@ -688,6 +688,8 @@
 		case MEDIUM_ERROR:
 			if (!(SCpnt->sense_buffer[0] & 0x80))
 				break;
+			if (!blk_fs_request(SCpnt->request))
+				break;
 			error_sector = (SCpnt->sense_buffer[3] << 24) |
 			(SCpnt->sense_buffer[4] << 16) |
 			(SCpnt->sense_buffer[5] << 8) |
@@ -718,9 +720,9 @@
 			}
 
 			error_sector &= ~(block_sectors - 1);
-			good_sectors = error_sector - SCpnt->request->sector;
-			if (good_sectors < 0 || good_sectors >= this_count)
-				good_sectors = 0;
+			good_bytes = (error_sector - SCpnt->request->sector) << 9;
+			if (good_bytes < 0 || good_bytes >= this_count)
+				good_bytes = 0;
 			break;
 
 		case RECOVERED_ERROR:
@@ -732,7 +734,7 @@
 			print_sense("sd", SCpnt);
 			SCpnt->result = 0;
 			SCpnt->sense_buffer[0] = 0x0;
-			good_sectors = this_count;
+			good_bytes = this_count;
 			break;
 
 		case ILLEGAL_REQUEST:
@@ -755,7 +757,7 @@
 	 * how many actual sectors finished, and how many sectors we need
 	 * to say have failed.
 	 */
-	scsi_io_completion(SCpnt, good_sectors, block_sectors);
+	scsi_io_completion(SCpnt, good_bytes, block_sectors << 9);
 }
 
 static int media_not_present(struct scsi_disk *sdkp, struct scsi_request *srp)
===== drivers/scsi/sr.c 1.98 vs edited =====
--- 1.98/drivers/scsi/sr.c	Mon Feb  9 21:59:10 2004
+++ edited/drivers/scsi/sr.c	Mon Feb 23 14:20:57 2004
@@ -179,14 +179,14 @@
 static void rw_intr(struct scsi_cmnd * SCpnt)
 {
 	int result = SCpnt->result;
-	int this_count = SCpnt->bufflen >> 9;
-	int good_sectors = (result == 0 ? this_count : 0);
+	int this_count = SCpnt->bufflen;
+	int good_bytes = (result == 0 ? this_count : 0);
 	int block_sectors = 0;
 	long error_sector;
 	struct scsi_cd *cd = scsi_cd(SCpnt->request->rq_disk);
 
 #ifdef DEBUG
-	printk("sr.c done: %x %p\n", result, SCpnt->request->bh->b_data);
+	printk("sr.c done: %x\n", result);
 #endif
 
 	/*
@@ -203,6 +203,8 @@
 		case ILLEGAL_REQUEST:
 			if (!(SCpnt->sense_buffer[0] & 0x90))
 				break;
+			if (!blk_fs_request(SCpnt->request))
+				break;
 			error_sector = (SCpnt->sense_buffer[3] << 24) |
 				(SCpnt->sense_buffer[4] << 16) |
 				(SCpnt->sense_buffer[5] << 8) |
@@ -215,9 +217,9 @@
 			if (cd->device->sector_size == 2048)
 				error_sector <<= 2;
 			error_sector &= ~(block_sectors - 1);
-			good_sectors = error_sector - SCpnt->request->sector;
-			if (good_sectors < 0 || good_sectors >= this_count)
-				good_sectors = 0;
+			good_bytes = (error_sector - SCpnt->request->sector) << 9;
+			if (good_bytes < 0 || good_bytes >= this_count)
+				good_bytes = 0;
 			/*
 			 * The SCSI specification allows for the value
 			 * returned by READ CAPACITY to be up to 75 2K
@@ -241,7 +243,7 @@
 			print_sense("sr", SCpnt);
 			SCpnt->result = 0;
 			SCpnt->sense_buffer[0] = 0x0;
-			good_sectors = this_count;
+			good_bytes = this_count;
 			break;
 
 		default:
@@ -254,7 +256,7 @@
 	 * how many actual sectors finished, and how many sectors we need
 	 * to say have failed.
 	 */
-	scsi_io_completion(SCpnt, good_sectors, block_sectors);
+	scsi_io_completion(SCpnt, good_bytes, block_sectors << 9);
 }
 
 static int sr_init_command(struct scsi_cmnd * SCpnt)
===== drivers/scsi/st.c 1.77 vs edited =====
--- 1.77/drivers/scsi/st.c	Fri Feb  6 09:21:37 2004
+++ edited/drivers/scsi/st.c	Mon Feb 23 14:23:46 2004
@@ -4011,7 +4011,7 @@
 
 static void st_intr(struct scsi_cmnd *SCpnt)
 {
-	scsi_io_completion(SCpnt, (SCpnt->result ? 0: SCpnt->bufflen >> 9), 1);
+	scsi_io_completion(SCpnt, (SCpnt->result ? 0: SCpnt->bufflen), 1);
 }
 
 /*
===== include/scsi/scsi_cmnd.h 1.3 vs edited =====
--- 1.3/include/scsi/scsi_cmnd.h	Sat Sep 20 11:36:20 2003
+++ edited/include/scsi/scsi_cmnd.h	Mon Feb 23 14:21:27 2004
@@ -158,6 +158,6 @@
 
 extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, int);
 extern void scsi_put_command(struct scsi_cmnd *);
-extern void scsi_io_completion(struct scsi_cmnd *, int, int);
+extern void scsi_io_completion(struct scsi_cmnd *, unsigned int, unsigned int);
 
 #endif /* _SCSI_SCSI_CMND_H */


-- 
Jens Axboe


  reply	other threads:[~2004-02-23 13:26 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-02-19 19:47 PROBLEM: 2.6.3 hangs when writing to scsi-dvd Joachim Feise
2004-02-20 22:13 ` Joachim Feise
2004-02-23 11:52   ` Kai Makisara
2004-02-23 13:26     ` Jens Axboe [this message]
2004-02-23 14:22       ` Kai Makisara
2004-02-23 14:25         ` Jens Axboe
2004-02-23 18:21           ` Frank Pieczynski
2004-02-23 19:05             ` Jens Axboe
2004-02-24  7:18           ` Joachim Feise
2004-02-23 13:46     ` mike
  -- strict thread matches above, loose matches on Subject: below --
2004-02-21 10:25 Michael Guntsche

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20040223132634.GD32010@suse.de \
    --to=axboe@suse.de \
    --cc=Kai.Makisara@kolumbus.fi \
    --cc=akpm@osdl.org \
    --cc=gibbs@scsiguy.com \
    --cc=jfeise@ics.uci.edu \
    --cc=linux-scsi@vger.kernel.org \
    --cc=mike@it-loops.com \
    --cc=pieczy@web.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox