Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 03aba2f7 authored by Luben Tuikov's avatar Luben Tuikov Committed by James Bottomley
Browse files

[SCSI] sd/scsi_lib simplify sd_rw_intr and scsi_io_completion



This patch simplifies "good_bytes" computation in sd_rw_intr().
sd: "good_bytes" computation is always done in terms of the resolution
of the device's medium, since after that it is the number of good bytes
we pass around and other layers/contexts (as opposed ot sd) can translate
that to their own resolution (block layer:512).  It also makes
scsi_io_completion() processing more straightforward, eliminating the
3rd argument to the function.

It also fixes a couple of bugs like not checking return value,
using "break" instead of "return;", etc.

I've been running with this patch for some time now on a
test (do-it-all) system.

Signed-off-by: default avatarLuben Tuikov <ltuikov@yahoo.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent f89d0a4e
Loading
Loading
Loading
Loading
+42 −66
Original line number Diff line number Diff line
@@ -855,8 +855,7 @@ static void scsi_release_buffers(struct scsi_cmnd *cmd)
 *		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, unsigned int good_bytes,
			unsigned int block_bytes)
void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
{
	int result = cmd->result;
	int this_count = cmd->bufflen;
@@ -921,51 +920,38 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
	 * Next deal with any sectors which we were able to correctly
	 * handle.
	 */
	if (good_bytes >= 0) {
		SCSI_LOG_HLCOMPLETE(1, printk("%ld sectors total, %d bytes done.\n",
	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)
			req->errors = 0;
		/*
		 * If multiple sectors are requested in one buffer, then
		 * they will have been finished off by the first command.
		 * If not, then we have a multi-buffer command.
		 *
		 * 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.
		 */

		/*
		 * If the command completed without error, then either
		 * finish off the rest of the command, or start a new one.
		/* A number of bytes were successfully read.  If there
		 * is leftovers and there is some kind of error
		 * (result != 0), retry the rest.
		 */
		if (scsi_end_request(cmd, 1, good_bytes, result == 0) == NULL)
		if (scsi_end_request(cmd, 1, good_bytes, !!result) == NULL)
			return;
	}
	/*
	 * Now, if we were good little boys and girls, Santa left us a request
	 * sense buffer.  We can extract information from this, so we
	 * can choose a block to remap, etc.

	/* good_bytes = 0, or (inclusive) there were leftovers and
	 * result = 0, so scsi_end_request couldn't retry.
	 */
	if (sense_valid && !sense_deferred) {
		switch (sshdr.sense_key) {
		case UNIT_ATTENTION:
			if (cmd->device->removable) {
				/* detected disc change.  set a bit 
				/* Detected disc change.  Set a bit
				 * and quietly refuse further access.
				 */
				cmd->device->changed = 1;
				scsi_end_request(cmd, 0,
						this_count, 1);
				scsi_end_request(cmd, 0, this_count, 1);
				return;
			} else {
				/*
				* Must have been a power glitch, or a
				/* Must have been a power glitch, or a
				 * bus reset.  Could not have been a
				 * media change, so we just retry the
				 * request and see what happens.
@@ -975,33 +961,31 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
			}
			break;
		case ILLEGAL_REQUEST:
			/*
		 	* If we had an ILLEGAL REQUEST returned, then we may
		 	* have performed an unsupported command.  The only
		 	* thing this should be would be a ten byte read where
			* only a six byte read was supported.  Also, on a
			* system where READ CAPACITY failed, we may have read
			* past the end of the disk.
			/* If we had an ILLEGAL REQUEST returned, then
			 * we may have performed an unsupported
			 * command.  The only thing this should be
			 * would be a ten byte read where only a six
			 * byte read was supported.  Also, on a system
			 * where READ CAPACITY failed, we may have
			 * read past the end of the disk.
			 */
			if ((cmd->device->use_10_for_rw &&
			    sshdr.asc == 0x20 && sshdr.ascq == 0x00) &&
			    (cmd->cmnd[0] == READ_10 ||
			     cmd->cmnd[0] == WRITE_10)) {
				cmd->device->use_10_for_rw = 0;
				/*
				 * This will cause a retry with a 6-byte
				 * command.
				/* This will cause a retry with a
				 * 6-byte command.
				 */
				scsi_requeue_command(q, cmd);
				result = 0;
				return;
			} else {
				scsi_end_request(cmd, 0, this_count, 1);
				return;
			}
			break;
		case NOT_READY:
			/*
			 * If the device is in the process of becoming
			/* If the device is in the process of becoming
			 * ready, or has a temporary blockage, retry.
			 */
			if (sshdr.asc == 0x04) {
@@ -1033,17 +1017,17 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
				__scsi_print_command(cmd->data_cmnd);
				scsi_print_sense("", cmd);
			}
			scsi_end_request(cmd, 0, block_bytes, 1);
			/* See SSC3rXX or current. */
			scsi_end_request(cmd, 0, this_count, 1);
			return;
		default:
			break;
		}
	}			/* driver byte != 0 */
	}
	if (host_byte(result) == DID_RESET) {
		/*
		 * Third party bus reset or reset for error
		 * recovery reasons.  Just retry the request
		 * and see what happens.  
		/* Third party bus reset or reset for error recovery
		 * reasons.  Just retry the request and see what
		 * happens.
		 */
		scsi_requeue_command(q, cmd);
		return;
@@ -1051,21 +1035,13 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
	if (result) {
		if (!(req->flags & REQ_QUIET)) {
			scmd_printk(KERN_INFO, cmd,
				   "SCSI error: return code = 0x%x\n", result);

				    "SCSI error: return code = 0x%08x\n",
				    result);
			if (driver_byte(result) & DRIVER_SENSE)
				scsi_print_sense("", cmd);
		}
		/*
		 * Mark a single buffer as not uptodate.  Queue the remainder.
		 * We sometimes get this cruft in the event that a medium error
		 * isn't properly reported.
		 */
		block_bytes = req->hard_cur_sectors << 9;
		if (!block_bytes)
			block_bytes = req->data_len;
		scsi_end_request(cmd, 0, block_bytes, 1);
	}
	scsi_end_request(cmd, 0, this_count, !result);
}
EXPORT_SYMBOL(scsi_io_completion);

@@ -1169,7 +1145,7 @@ static void scsi_blk_pc_done(struct scsi_cmnd *cmd)
	 * successfully. Since this is a REQ_BLOCK_PC command the
	 * caller should check the request's errors value
	 */
	scsi_io_completion(cmd, cmd->bufflen, 0);
	scsi_io_completion(cmd, cmd->bufflen);
}

static void scsi_setup_blk_pc_cmnd(struct scsi_cmnd *cmd)
+62 −81
Original line number Diff line number Diff line
@@ -891,11 +891,10 @@ static struct block_device_operations sd_fops = {
static void sd_rw_intr(struct scsi_cmnd * SCpnt)
{
	int result = SCpnt->result;
	int this_count = SCpnt->request_bufflen;
	int good_bytes = (result == 0 ? this_count : 0);
	sector_t block_sectors = 1;
	u64 first_err_block;
	sector_t error_sector;
 	unsigned int xfer_size = SCpnt->request_bufflen;
 	unsigned int good_bytes = result ? 0 : xfer_size;
 	u64 start_lba = SCpnt->request->sector;
 	u64 bad_lba;
	struct scsi_sense_hdr sshdr;
	int sense_valid = 0;
	int sense_deferred = 0;
@@ -906,7 +905,6 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
		if (sense_valid)
			sense_deferred = scsi_sense_is_deferred(&sshdr);
	}

#ifdef CONFIG_SCSI_LOGGING
	SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: %s: res=0x%x\n", 
				SCpnt->request->rq_disk->disk_name, result));
@@ -916,68 +914,57 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
				sshdr.sense_key, sshdr.asc, sshdr.ascq));
	}
#endif
	/*
	   Handle MEDIUM ERRORs that indicate partial success.  Since this is a
	   relatively rare error condition, no care is taken to avoid
	   unnecessary additional work such as memcpy's that could be avoided.
	 */
	if (driver_byte(result) != 0 &&
		 sense_valid && !sense_deferred) {
	if (driver_byte(result) != DRIVER_SENSE &&
	    (!sense_valid || sense_deferred))
		goto out;

	switch (sshdr.sense_key) {
	case HARDWARE_ERROR:
	case MEDIUM_ERROR:
		if (!blk_fs_request(SCpnt->request))
				break;
			info_valid = scsi_get_sense_info_fld(
				SCpnt->sense_buffer, SCSI_SENSE_BUFFERSIZE,
				&first_err_block);
			/*
			 * May want to warn and skip if following cast results
			 * in actual truncation (if sector_t < 64 bits)
			 */
			error_sector = (sector_t)first_err_block;
			if (SCpnt->request->bio != NULL)
				block_sectors = bio_sectors(SCpnt->request->bio);
			goto out;
		info_valid = scsi_get_sense_info_fld(SCpnt->sense_buffer,
						     SCSI_SENSE_BUFFERSIZE,
						     &bad_lba);
		if (!info_valid)
			goto out;
		if (xfer_size <= SCpnt->device->sector_size)
			goto out;
		switch (SCpnt->device->sector_size) {
		case 256:
			start_lba <<= 1;
			break;
		case 512:
			break;
		case 1024:
				error_sector <<= 1;
				if (block_sectors < 2)
					block_sectors = 2;
			start_lba >>= 1;
			break;
		case 2048:
				error_sector <<= 2;
				if (block_sectors < 4)
					block_sectors = 4;
			start_lba >>= 2;
			break;
		case 4096:
				error_sector <<=3;
				if (block_sectors < 8)
					block_sectors = 8;
				break;
			case 256:
				error_sector >>= 1;
			start_lba >>= 3;
			break;
		default:
			/* Print something here with limiting frequency. */
			goto out;
			break;
		}

			error_sector &= ~(block_sectors - 1);
			good_bytes = (error_sector - SCpnt->request->sector) << 9;
			if (good_bytes < 0 || good_bytes >= this_count)
				good_bytes = 0;
		/* This computation should always be done in terms of
		 * the resolution of the device's medium.
		 */
		good_bytes = (bad_lba - start_lba)*SCpnt->device->sector_size;
		break;

		case RECOVERED_ERROR: /* an error occurred, but it recovered */
		case NO_SENSE: /* LLDD got sense data */
			/*
			 * Inform the user, but make sure that it's not treated
	case RECOVERED_ERROR:
	case NO_SENSE:
		/* Inform the user, but make sure that it's not treated
		 * as a hard error.
		 */
		scsi_print_sense("sd", SCpnt);
		SCpnt->result = 0;
		memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
			good_bytes = this_count;
		good_bytes = xfer_size;
		break;

	case ILLEGAL_REQUEST:
		if (SCpnt->device->use_10_for_rw &&
		    (SCpnt->cmnd[0] == READ_10 ||
@@ -988,17 +975,11 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
		     SCpnt->cmnd[0] == MODE_SELECT_10))
			SCpnt->device->use_10_for_ms = 0;
		break;

	default:
		break;
	}
	}
	/*
	 * This calls the generic completion function, now that we know
	 * how many actual sectors finished, and how many sectors we need
	 * to say have failed.
	 */
	scsi_io_completion(SCpnt, good_bytes, block_sectors << 9);
 out:
	scsi_io_completion(SCpnt, good_bytes);
}

static int media_not_present(struct scsi_disk *sdkp,
+1 −1
Original line number Diff line number Diff line
@@ -292,7 +292,7 @@ static void rw_intr(struct scsi_cmnd * SCpnt)
	 * how many actual sectors finished, and how many sectors we need
	 * to say have failed.
	 */
	scsi_io_completion(SCpnt, good_bytes, block_sectors << 9);
	scsi_io_completion(SCpnt, good_bytes);
}

static int sr_init_command(struct scsi_cmnd * SCpnt)
+1 −1
Original line number Diff line number Diff line
@@ -143,7 +143,7 @@ struct scsi_cmnd {

extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t);
extern void scsi_put_command(struct scsi_cmnd *);
extern void scsi_io_completion(struct scsi_cmnd *, unsigned int, unsigned int);
extern void scsi_io_completion(struct scsi_cmnd *, unsigned int);
extern void scsi_finish_command(struct scsi_cmnd *cmd);
extern void scsi_req_abort_cmd(struct scsi_cmnd *cmd);