diff options
Diffstat (limited to 'drivers/scsi/sd.c')
| -rw-r--r-- | drivers/scsi/sd.c | 228 | 
1 files changed, 136 insertions, 92 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index e62d17d41d4..6825eda1114 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -105,11 +105,14 @@ static void sd_unlock_native_capacity(struct gendisk *disk);  static int  sd_probe(struct device *);  static int  sd_remove(struct device *);  static void sd_shutdown(struct device *); -static int sd_suspend(struct device *); +static int sd_suspend_system(struct device *); +static int sd_suspend_runtime(struct device *);  static int sd_resume(struct device *);  static void sd_rescan(struct device *); +static int sd_init_command(struct scsi_cmnd *SCpnt); +static void sd_uninit_command(struct scsi_cmnd *SCpnt);  static int sd_done(struct scsi_cmnd *); -static int sd_eh_action(struct scsi_cmnd *, unsigned char *, int, int); +static int sd_eh_action(struct scsi_cmnd *, int);  static void sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer);  static void scsi_disk_release(struct device *cdev);  static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *); @@ -484,11 +487,11 @@ static struct class sd_disk_class = {  };  static const struct dev_pm_ops sd_pm_ops = { -	.suspend		= sd_suspend, +	.suspend		= sd_suspend_system,  	.resume			= sd_resume, -	.poweroff		= sd_suspend, +	.poweroff		= sd_suspend_system,  	.restore		= sd_resume, -	.runtime_suspend	= sd_suspend, +	.runtime_suspend	= sd_suspend_runtime,  	.runtime_resume		= sd_resume,  }; @@ -502,6 +505,8 @@ static struct scsi_driver sd_template = {  		.pm		= &sd_pm_ops,  	},  	.rescan			= sd_rescan, +	.init_command		= sd_init_command, +	.uninit_command		= sd_uninit_command,  	.done			= sd_done,  	.eh_action		= sd_eh_action,  }; @@ -736,16 +741,14 @@ static int sd_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq)  		goto out;  	} +	rq->completion_data = page;  	blk_add_request_payload(rq, page, len);  	ret = scsi_setup_blk_pc_cmnd(sdp, rq); -	rq->buffer = page_address(page);  	rq->__data_len = nr_bytes;  out: -	if (ret != BLKPREP_OK) { +	if (ret != BLKPREP_OK)  		__free_page(page); -		rq->buffer = NULL; -	}  	return ret;  } @@ -800,7 +803,7 @@ static int sd_setup_write_same_cmnd(struct scsi_device *sdp, struct request *rq)  	if (sdkp->device->no_write_same)  		return BLKPREP_KILL; -	BUG_ON(bio_offset(bio) || bio_iovec(bio)->bv_len != sdp->sector_size); +	BUG_ON(bio_offset(bio) || bio_iovec(bio).bv_len != sdp->sector_size);  	sector >>= ilog2(sdp->sector_size) - 9;  	nr_sectors >>= ilog2(sdp->sector_size) - 9; @@ -829,7 +832,7 @@ static int sd_setup_write_same_cmnd(struct scsi_device *sdp, struct request *rq)  static int scsi_setup_flush_cmnd(struct scsi_device *sdp, struct request *rq)  { -	rq->timeout = SD_FLUSH_TIMEOUT; +	rq->timeout *= SD_FLUSH_TIMEOUT_MULTIPLIER;  	rq->retries = SD_MAX_RETRIES;  	rq->cmd[0] = SYNCHRONIZE_CACHE;  	rq->cmd_len = 10; @@ -837,14 +840,13 @@ static int scsi_setup_flush_cmnd(struct scsi_device *sdp, struct request *rq)  	return scsi_setup_blk_pc_cmnd(sdp, rq);  } -static void sd_unprep_fn(struct request_queue *q, struct request *rq) +static void sd_uninit_command(struct scsi_cmnd *SCpnt)  { -	struct scsi_cmnd *SCpnt = rq->special; +	struct request *rq = SCpnt->request; + +	if (rq->cmd_flags & REQ_DISCARD) +		__free_page(rq->completion_data); -	if (rq->cmd_flags & REQ_DISCARD) { -		free_page((unsigned long)rq->buffer); -		rq->buffer = NULL; -	}  	if (SCpnt->cmnd != rq->cmd) {  		mempool_free(SCpnt->cmnd, sd_cdb_pool);  		SCpnt->cmnd = NULL; @@ -852,18 +854,10 @@ static void sd_unprep_fn(struct request_queue *q, struct request *rq)  	}  } -/** - *	sd_prep_fn - build a scsi (read or write) command from - *	information in the request structure. - *	@SCpnt: pointer to mid-level's per scsi command structure that - *	contains request and into which the scsi command is written - * - *	Returns 1 if successful and 0 if error (or cannot be done now). - **/ -static int sd_prep_fn(struct request_queue *q, struct request *rq) +static int sd_init_command(struct scsi_cmnd *SCpnt)  { -	struct scsi_cmnd *SCpnt; -	struct scsi_device *sdp = q->queuedata; +	struct request *rq = SCpnt->request; +	struct scsi_device *sdp = SCpnt->device;  	struct gendisk *disk = rq->rq_disk;  	struct scsi_disk *sdkp;  	sector_t block = blk_rq_pos(rq); @@ -885,12 +879,6 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)  	} else if (rq->cmd_flags & REQ_FLUSH) {  		ret = scsi_setup_flush_cmnd(sdp, rq);  		goto out; -	} else if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { -		ret = scsi_setup_blk_pc_cmnd(sdp, rq); -		goto out; -	} else if (rq->cmd_type != REQ_TYPE_FS) { -		ret = BLKPREP_KILL; -		goto out;  	}  	ret = scsi_setup_fs_cmnd(sdp, rq);  	if (ret != BLKPREP_OK) @@ -902,11 +890,10 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)  	 * is used for a killable error condition */  	ret = BLKPREP_KILL; -	SCSI_LOG_HLQUEUE(1, scmd_printk(KERN_INFO, SCpnt, -					"sd_prep_fn: block=%llu, " -					"count=%d\n", -					(unsigned long long)block, -					this_count)); +	SCSI_LOG_HLQUEUE(1, +		scmd_printk(KERN_INFO, SCpnt, +			"%s: block=%llu, count=%d\n", +			__func__, (unsigned long long)block, this_count));  	if (!sdp || !scsi_device_online(sdp) ||  	    block + blk_rq_sectors(rq) > get_capacity(disk)) { @@ -1002,7 +989,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)  		SCpnt->cmnd[0] = READ_6;  		SCpnt->sc_data_direction = DMA_FROM_DEVICE;  	} else { -		scmd_printk(KERN_ERR, SCpnt, "Unknown command %x\n", rq->cmd_flags); +		scmd_printk(KERN_ERR, SCpnt, "Unknown command %llx\n", (unsigned long long) rq->cmd_flags);  		goto out;  	} @@ -1126,7 +1113,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)  	 */  	ret = BLKPREP_OK;   out: -	return scsi_prep_return(q, rq, ret); +	return ret;  }  /** @@ -1433,12 +1420,13 @@ static int sd_sync_cache(struct scsi_disk *sdkp)  {  	int retries, res;  	struct scsi_device *sdp = sdkp->device; +	const int timeout = sdp->request_queue->rq_timeout +		* SD_FLUSH_TIMEOUT_MULTIPLIER;  	struct scsi_sense_hdr sshdr;  	if (!scsi_device_online(sdp))  		return -ENODEV; -  	for (retries = 3; retries > 0; --retries) {  		unsigned char cmd[10] = { 0 }; @@ -1448,20 +1436,39 @@ static int sd_sync_cache(struct scsi_disk *sdkp)  		 * flush everything.  		 */  		res = scsi_execute_req_flags(sdp, cmd, DMA_NONE, NULL, 0, -					     &sshdr, SD_FLUSH_TIMEOUT, -					     SD_MAX_RETRIES, NULL, REQ_PM); +					     &sshdr, timeout, SD_MAX_RETRIES, +					     NULL, REQ_PM);  		if (res == 0)  			break;  	}  	if (res) {  		sd_print_result(sdkp, res); +  		if (driver_byte(res) & DRIVER_SENSE)  			sd_print_sense_hdr(sdkp, &sshdr); +		/* we need to evaluate the error return  */ +		if (scsi_sense_valid(&sshdr) && +			(sshdr.asc == 0x3a ||	/* medium not present */ +			 sshdr.asc == 0x20))	/* invalid command */ +				/* this is no error here */ +				return 0; + +		switch (host_byte(res)) { +		/* ignore errors due to racing a disconnection */ +		case DID_BAD_TARGET: +		case DID_NO_CONNECT: +			return 0; +		/* signal the upper layer it might try again */ +		case DID_BUS_BUSY: +		case DID_IMM_RETRY: +		case DID_REQUEUE: +		case DID_SOFT_ERROR: +			return -EBUSY; +		default: +			return -EIO; +		}  	} - -	if (res) -		return -EIO;  	return 0;  } @@ -1530,23 +1537,23 @@ static const struct block_device_operations sd_fops = {  /**   *	sd_eh_action - error handling callback   *	@scmd:		sd-issued command that has failed - *	@eh_cmnd:	The command that was sent during error handling - *	@eh_cmnd_len:	Length of eh_cmnd in bytes   *	@eh_disp:	The recovery disposition suggested by the midlayer   * - *	This function is called by the SCSI midlayer upon completion of - *	an error handling command (TEST UNIT READY, START STOP UNIT, - *	etc.) The command sent to the device by the error handler is - *	stored in eh_cmnd. The result of sending the eh command is - *	passed in eh_disp. + *	This function is called by the SCSI midlayer upon completion of an + *	error test command (currently TEST UNIT READY). The result of sending + *	the eh command is passed in eh_disp.  We're looking for devices that + *	fail medium access commands but are OK with non access commands like + *	test unit ready (so wrongly see the device as having a successful + *	recovery)   **/ -static int sd_eh_action(struct scsi_cmnd *scmd, unsigned char *eh_cmnd, -			int eh_cmnd_len, int eh_disp) +static int sd_eh_action(struct scsi_cmnd *scmd, int eh_disp)  {  	struct scsi_disk *sdkp = scsi_disk(scmd->request->rq_disk);  	if (!scsi_device_online(scmd->device) || -	    !scsi_medium_access_command(scmd)) +	    !scsi_medium_access_command(scmd) || +	    host_byte(scmd->result) != DID_TIME_OUT || +	    eh_disp != SUCCESS)  		return eh_disp;  	/* @@ -1556,9 +1563,7 @@ static int sd_eh_action(struct scsi_cmnd *scmd, unsigned char *eh_cmnd,  	 * process of recovering or has it suffered an internal failure  	 * that prevents access to the storage medium.  	 */ -	if (host_byte(scmd->result) == DID_TIME_OUT && eh_disp == SUCCESS && -	    eh_cmnd_len && eh_cmnd[0] == TEST_UNIT_READY) -		sdkp->medium_access_timed_out++; +	sdkp->medium_access_timed_out++;  	/*  	 * If the device keeps failing read/write commands but TEST UNIT @@ -1607,7 +1612,7 @@ static unsigned int sd_completed_bytes(struct scsi_cmnd *scmd)  		end_lba <<= 1;  	} else {  		/* be careful ... don't want any overflows */ -		u64 factor = scmd->device->sector_size / 512; +		unsigned int factor = scmd->device->sector_size / 512;  		do_div(start_lba, factor);  		do_div(end_lba, factor);  	} @@ -1670,12 +1675,12 @@ static int sd_done(struct scsi_cmnd *SCpnt)  						   sshdr.ascq));  	}  #endif +	sdkp->medium_access_timed_out = 0; +  	if (driver_byte(result) != DRIVER_SENSE &&  	    (!sense_valid || sense_deferred))  		goto out; -	sdkp->medium_access_timed_out = 0; -  	switch (sshdr.sense_key) {  	case HARDWARE_ERROR:  	case MEDIUM_ERROR: @@ -2262,7 +2267,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer)  	set_disk_ro(sdkp->disk, 0);  	if (sdp->skip_ms_page_3f) { -		sd_printk(KERN_NOTICE, sdkp, "Assuming Write Enabled\n"); +		sd_first_printk(KERN_NOTICE, sdkp, "Assuming Write Enabled\n");  		return;  	} @@ -2294,7 +2299,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer)  	}  	if (!scsi_status_is_good(res)) { -		sd_printk(KERN_WARNING, sdkp, +		sd_first_printk(KERN_WARNING, sdkp,  			  "Test WP failed, assume Write Enabled\n");  	} else {  		sdkp->write_prot = ((data.device_specific & 0x80) != 0); @@ -2362,7 +2367,8 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)  	if (!data.header_length) {  		modepage = 6;  		first_len = 0; -		sd_printk(KERN_ERR, sdkp, "Missing header in MODE_SENSE response\n"); +		sd_first_printk(KERN_ERR, sdkp, +				"Missing header in MODE_SENSE response\n");  	}  	/* that went OK, now ask for the proper length */ @@ -2375,7 +2381,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)  	if (len < 3)  		goto bad_sense;  	else if (len > SD_BUF_SIZE) { -		sd_printk(KERN_NOTICE, sdkp, "Truncating mode parameter " +		sd_first_printk(KERN_NOTICE, sdkp, "Truncating mode parameter "  			  "data from %d to %d bytes\n", len, SD_BUF_SIZE);  		len = SD_BUF_SIZE;  	} @@ -2398,8 +2404,9 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)  				/* We're interested only in the first 3 bytes.  				 */  				if (len - offset <= 2) { -					sd_printk(KERN_ERR, sdkp, "Incomplete " -						  "mode parameter data\n"); +					sd_first_printk(KERN_ERR, sdkp, +						"Incomplete mode parameter " +							"data\n");  					goto defaults;  				} else {  					modepage = page_code; @@ -2413,14 +2420,15 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)  				else if (!spf && len - offset > 1)  					offset += 2 + buffer[offset+1];  				else { -					sd_printk(KERN_ERR, sdkp, "Incomplete " -						  "mode parameter data\n"); +					sd_first_printk(KERN_ERR, sdkp, +							"Incomplete mode " +							"parameter data\n");  					goto defaults;  				}  			}  		} -		sd_printk(KERN_ERR, sdkp, "No Caching mode page found\n"); +		sd_first_printk(KERN_ERR, sdkp, "No Caching mode page found\n");  		goto defaults;  	Page_found: @@ -2433,8 +2441,11 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)  		}  		sdkp->DPOFUA = (data.device_specific & 0x10) != 0; -		if (sdkp->DPOFUA && !sdkp->device->use_10_for_rw) { -			sd_printk(KERN_NOTICE, sdkp, +		if (sdp->broken_fua) { +			sd_first_printk(KERN_NOTICE, sdkp, "Disabling FUA\n"); +			sdkp->DPOFUA = 0; +		} else if (sdkp->DPOFUA && !sdkp->device->use_10_for_rw) { +			sd_first_printk(KERN_NOTICE, sdkp,  				  "Uses READ/WRITE(6), disabling FUA\n");  			sdkp->DPOFUA = 0;  		} @@ -2456,16 +2467,19 @@ bad_sense:  	    sshdr.sense_key == ILLEGAL_REQUEST &&  	    sshdr.asc == 0x24 && sshdr.ascq == 0x0)  		/* Invalid field in CDB */ -		sd_printk(KERN_NOTICE, sdkp, "Cache data unavailable\n"); +		sd_first_printk(KERN_NOTICE, sdkp, "Cache data unavailable\n");  	else -		sd_printk(KERN_ERR, sdkp, "Asking for cache data failed\n"); +		sd_first_printk(KERN_ERR, sdkp, +				"Asking for cache data failed\n");  defaults:  	if (sdp->wce_default_on) { -		sd_printk(KERN_NOTICE, sdkp, "Assuming drive cache: write back\n"); +		sd_first_printk(KERN_NOTICE, sdkp, +				"Assuming drive cache: write back\n");  		sdkp->WCE = 1;  	} else { -		sd_printk(KERN_ERR, sdkp, "Assuming drive cache: write through\n"); +		sd_first_printk(KERN_ERR, sdkp, +				"Assuming drive cache: write through\n");  		sdkp->WCE = 0;  	}  	sdkp->RCD = 0; @@ -2494,7 +2508,7 @@ static void sd_read_app_tag_own(struct scsi_disk *sdkp, unsigned char *buffer)  	if (!scsi_status_is_good(res) || !data.header_length ||  	    data.length < 6) { -		sd_printk(KERN_WARNING, sdkp, +		sd_first_printk(KERN_WARNING, sdkp,  			  "getting Control mode page failed, assume no ATO\n");  		if (scsi_sense_valid(&sshdr)) @@ -2506,7 +2520,7 @@ static void sd_read_app_tag_own(struct scsi_disk *sdkp, unsigned char *buffer)  	offset = data.header_length + data.block_descriptor_length;  	if ((buffer[offset] & 0x3f) != 0x0a) { -		sd_printk(KERN_ERR, sdkp, "ATO Got wrong page\n"); +		sd_first_printk(KERN_ERR, sdkp, "ATO Got wrong page\n");  		return;  	} @@ -2638,14 +2652,23 @@ static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer)  {  	struct scsi_device *sdev = sdkp->device; +	if (sdev->host->no_write_same) { +		sdev->no_write_same = 1; + +		return; +	} +  	if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, INQUIRY) < 0) { +		/* too large values might cause issues with arcmsr */ +		int vpd_buf_len = 64; +  		sdev->no_report_opcodes = 1;  		/* Disable WRITE SAME if REPORT SUPPORTED OPERATION  		 * CODES is unsupported and the device has an ATA  		 * Information VPD page (SAT).  		 */ -		if (!scsi_get_vpd_page(sdev, 0x89, buffer, SD_BUF_SIZE)) +		if (!scsi_get_vpd_page(sdev, 0x89, buffer, vpd_buf_len))  			sdev->no_write_same = 1;  	} @@ -2844,9 +2867,6 @@ static void sd_probe_async(void *data, async_cookie_t cookie)  	sd_revalidate_disk(gd); -	blk_queue_prep_rq(sdp->request_queue, sd_prep_fn); -	blk_queue_unprep_rq(sdp->request_queue, sd_unprep_fn); -  	gd->driverfs_dev = &sdp->sdev_gendev;  	gd->flags = GENHD_FL_EXT_DEVT;  	if (sdp->removable) { @@ -2854,6 +2874,7 @@ static void sd_probe_async(void *data, async_cookie_t cookie)  		gd->events |= DISK_EVENT_MEDIA_CHANGE;  	} +	blk_pm_runtime_init(sdp->request_queue, dev);  	add_disk(gd);  	if (sdkp->capacity)  		sd_dif_config_host(sdkp); @@ -2862,7 +2883,6 @@ static void sd_probe_async(void *data, async_cookie_t cookie)  	sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",  		  sdp->removable ? "removable " : ""); -	blk_pm_runtime_init(sdp->request_queue, dev);  	scsi_autopm_put_device(sdp);  	put_device(&sdkp->dev);  } @@ -2992,9 +3012,8 @@ static int sd_remove(struct device *dev)  	devt = disk_devt(sdkp->disk);  	scsi_autopm_get_device(sdkp->device); +	async_synchronize_full_domain(&scsi_sd_pm_domain);  	async_synchronize_full_domain(&scsi_sd_probe_domain); -	blk_queue_prep_rq(sdkp->device->request_queue, scsi_prep_fn); -	blk_queue_unprep_rq(sdkp->device->request_queue, NULL);  	device_del(&sdkp->dev);  	del_gendisk(sdkp->disk);  	sd_shutdown(dev); @@ -3058,9 +3077,17 @@ static int sd_start_stop_device(struct scsi_disk *sdkp, int start)  		sd_print_result(sdkp, res);  		if (driver_byte(res) & DRIVER_SENSE)  			sd_print_sense_hdr(sdkp, &sshdr); +		if (scsi_sense_valid(&sshdr) && +			/* 0x3a is medium not present */ +			sshdr.asc == 0x3a) +			res = 0;  	} -	return res; +	/* SCSI error codes must not go to the generic layer */ +	if (res) +		return -EIO; + +	return 0;  }  /* @@ -3078,7 +3105,7 @@ static void sd_shutdown(struct device *dev)  	if (pm_runtime_suspended(dev))  		goto exit; -	if (sdkp->WCE) { +	if (sdkp->WCE && sdkp->media_present) {  		sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n");  		sd_sync_cache(sdkp);  	} @@ -3092,7 +3119,7 @@ exit:  	scsi_disk_put(sdkp);  } -static int sd_suspend(struct device *dev) +static int sd_suspend_common(struct device *dev, bool ignore_stop_errors)  {  	struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);  	int ret = 0; @@ -3100,16 +3127,23 @@ static int sd_suspend(struct device *dev)  	if (!sdkp)  		return 0;	/* this can happen */ -	if (sdkp->WCE) { +	if (sdkp->WCE && sdkp->media_present) {  		sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n");  		ret = sd_sync_cache(sdkp); -		if (ret) +		if (ret) { +			/* ignore OFFLINE device */ +			if (ret == -ENODEV) +				ret = 0;  			goto done; +		}  	}  	if (sdkp->device->manage_start_stop) {  		sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n"); +		/* an error is not worth aborting a system sleep */  		ret = sd_start_stop_device(sdkp, 0); +		if (ignore_stop_errors) +			ret = 0;  	}  done: @@ -3117,6 +3151,16 @@ done:  	return ret;  } +static int sd_suspend_system(struct device *dev) +{ +	return sd_suspend_common(dev, true); +} + +static int sd_suspend_runtime(struct device *dev) +{ +	return sd_suspend_common(dev, false); +} +  static int sd_resume(struct device *dev)  {  	struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);  | 
