⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 libata-scsi.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
 *	current command. * *	LOCKING: *	spin_lock_irqsave(host lock) * *	RETURNS: *	Command allocated, or %NULL if none available. */static struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,					      struct scsi_cmnd *cmd,					      void (*done)(struct scsi_cmnd *)){	struct ata_queued_cmd *qc;	qc = ata_qc_new_init(dev);	if (qc) {		qc->scsicmd = cmd;		qc->scsidone = done;		qc->__sg = scsi_sglist(cmd);		qc->n_elem = scsi_sg_count(cmd);	} else {		cmd->result = (DID_OK << 16) | (QUEUE_FULL << 1);		done(cmd);	}	return qc;}/** *	ata_dump_status - user friendly display of error info *	@id: id of the port in question *	@tf: ptr to filled out taskfile * *	Decode and dump the ATA error/status registers for the user so *	that they have some idea what really happened at the non *	make-believe layer. * *	LOCKING: *	inherited from caller */static void ata_dump_status(unsigned id, struct ata_taskfile *tf){	u8 stat = tf->command, err = tf->feature;	printk(KERN_WARNING "ata%u: status=0x%02x { ", id, stat);	if (stat & ATA_BUSY) {		printk("Busy }\n");	/* Data is not valid in this case */	} else {		if (stat & 0x40)	printk("DriveReady ");		if (stat & 0x20)	printk("DeviceFault ");		if (stat & 0x10)	printk("SeekComplete ");		if (stat & 0x08)	printk("DataRequest ");		if (stat & 0x04)	printk("CorrectedError ");		if (stat & 0x02)	printk("Index ");		if (stat & 0x01)	printk("Error ");		printk("}\n");		if (err) {			printk(KERN_WARNING "ata%u: error=0x%02x { ", id, err);			if (err & 0x04)		printk("DriveStatusError ");			if (err & 0x80) {				if (err & 0x04)	printk("BadCRC ");				else		printk("Sector ");			}			if (err & 0x40)		printk("UncorrectableError ");			if (err & 0x10)		printk("SectorIdNotFound ");			if (err & 0x02)		printk("TrackZeroNotFound ");			if (err & 0x01)		printk("AddrMarkNotFound ");			printk("}\n");		}	}}/** *	ata_to_sense_error - convert ATA error to SCSI error *	@id: ATA device number *	@drv_stat: value contained in ATA status register *	@drv_err: value contained in ATA error register *	@sk: the sense key we'll fill out *	@asc: the additional sense code we'll fill out *	@ascq: the additional sense code qualifier we'll fill out *	@verbose: be verbose * *	Converts an ATA error into a SCSI error.  Fill out pointers to *	SK, ASC, and ASCQ bytes for later use in fixed or descriptor *	format sense blocks. * *	LOCKING: *	spin_lock_irqsave(host lock) */static void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk,			       u8 *asc, u8 *ascq, int verbose){	int i;	/* Based on the 3ware driver translation table */	static const unsigned char sense_table[][4] = {		/* BBD|ECC|ID|MAR */		{0xd1, 		ABORTED_COMMAND, 0x00, 0x00}, 	// Device busy                  Aborted command		/* BBD|ECC|ID */		{0xd0,  	ABORTED_COMMAND, 0x00, 0x00}, 	// Device busy                  Aborted command		/* ECC|MC|MARK */		{0x61, 		HARDWARE_ERROR, 0x00, 0x00}, 	// Device fault                 Hardware error		/* ICRC|ABRT */		/* NB: ICRC & !ABRT is BBD */		{0x84, 		ABORTED_COMMAND, 0x47, 0x00}, 	// Data CRC error               SCSI parity error		/* MC|ID|ABRT|TRK0|MARK */		{0x37, 		NOT_READY, 0x04, 0x00}, 	// Unit offline                 Not ready		/* MCR|MARK */		{0x09, 		NOT_READY, 0x04, 0x00}, 	// Unrecovered disk error       Not ready		/*  Bad address mark */		{0x01, 		MEDIUM_ERROR, 0x13, 0x00}, 	// Address mark not found       Address mark not found for data field		/* TRK0 */		{0x02, 		HARDWARE_ERROR, 0x00, 0x00}, 	// Track 0 not found		  Hardware error		/* Abort & !ICRC */		{0x04, 		ABORTED_COMMAND, 0x00, 0x00}, 	// Aborted command              Aborted command		/* Media change request */		{0x08, 		NOT_READY, 0x04, 0x00}, 	// Media change request	  FIXME: faking offline		/* SRV */		{0x10, 		ABORTED_COMMAND, 0x14, 0x00}, 	// ID not found                 Recorded entity not found		/* Media change */		{0x08,  	NOT_READY, 0x04, 0x00}, 	// Media change		  FIXME: faking offline		/* ECC */		{0x40, 		MEDIUM_ERROR, 0x11, 0x04}, 	// Uncorrectable ECC error      Unrecovered read error		/* BBD - block marked bad */		{0x80, 		MEDIUM_ERROR, 0x11, 0x04}, 	// Block marked bad		  Medium error, unrecovered read error		{0xFF, 0xFF, 0xFF, 0xFF}, // END mark	};	static const unsigned char stat_table[][4] = {		/* Must be first because BUSY means no other bits valid */		{0x80, 		ABORTED_COMMAND, 0x47, 0x00},	// Busy, fake parity for now		{0x20, 		HARDWARE_ERROR,  0x00, 0x00}, 	// Device fault		{0x08, 		ABORTED_COMMAND, 0x47, 0x00},	// Timed out in xfer, fake parity for now		{0x04, 		RECOVERED_ERROR, 0x11, 0x00},	// Recovered ECC error	  Medium error, recovered		{0xFF, 0xFF, 0xFF, 0xFF}, // END mark	};	/*	 *	Is this an error we can process/parse	 */	if (drv_stat & ATA_BUSY) {		drv_err = 0;	/* Ignore the err bits, they're invalid */	}	if (drv_err) {		/* Look for drv_err */		for (i = 0; sense_table[i][0] != 0xFF; i++) {			/* Look for best matches first */			if ((sense_table[i][0] & drv_err) ==			    sense_table[i][0]) {				*sk = sense_table[i][1];				*asc = sense_table[i][2];				*ascq = sense_table[i][3];				goto translate_done;			}		}		/* No immediate match */		if (verbose)			printk(KERN_WARNING "ata%u: no sense translation for "			       "error 0x%02x\n", id, drv_err);	}	/* Fall back to interpreting status bits */	for (i = 0; stat_table[i][0] != 0xFF; i++) {		if (stat_table[i][0] & drv_stat) {			*sk = stat_table[i][1];			*asc = stat_table[i][2];			*ascq = stat_table[i][3];			goto translate_done;		}	}	/* No error?  Undecoded? */	if (verbose)		printk(KERN_WARNING "ata%u: no sense translation for "		       "status: 0x%02x\n", id, drv_stat);	/* We need a sensible error return here, which is tricky, and one	   that won't cause people to do things like return a disk wrongly */	*sk = ABORTED_COMMAND;	*asc = 0x00;	*ascq = 0x00; translate_done:	if (verbose)		printk(KERN_ERR "ata%u: translated ATA stat/err 0x%02x/%02x "		       "to SCSI SK/ASC/ASCQ 0x%x/%02x/%02x\n",		       id, drv_stat, drv_err, *sk, *asc, *ascq);	return;}/* *	ata_gen_passthru_sense - Generate check condition sense block. *	@qc: Command that completed. * *	This function is specific to the ATA descriptor format sense *	block specified for the ATA pass through commands.  Regardless *	of whether the command errored or not, return a sense *	block. Copy all controller registers into the sense *	block. Clear sense key, ASC & ASCQ if there is no error. * *	LOCKING: *	None. */static void ata_gen_passthru_sense(struct ata_queued_cmd *qc){	struct scsi_cmnd *cmd = qc->scsicmd;	struct ata_taskfile *tf = &qc->result_tf;	unsigned char *sb = cmd->sense_buffer;	unsigned char *desc = sb + 8;	int verbose = qc->ap->ops->error_handler == NULL;	memset(sb, 0, SCSI_SENSE_BUFFERSIZE);	cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;	/*	 * Use ata_to_sense_error() to map status register bits	 * onto sense key, asc & ascq.	 */	if (qc->err_mask ||	    tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) {		ata_to_sense_error(qc->ap->print_id, tf->command, tf->feature,				   &sb[1], &sb[2], &sb[3], verbose);		sb[1] &= 0x0f;	}	/*	 * Sense data is current and format is descriptor.	 */	sb[0] = 0x72;	desc[0] = 0x09;	/* set length of additional sense data */	sb[7] = 14;	desc[1] = 12;	/*	 * Copy registers into sense buffer.	 */	desc[2] = 0x00;	desc[3] = tf->feature;	/* == error reg */	desc[5] = tf->nsect;	desc[7] = tf->lbal;	desc[9] = tf->lbam;	desc[11] = tf->lbah;	desc[12] = tf->device;	desc[13] = tf->command; /* == status reg */	/*	 * Fill in Extend bit, and the high order bytes	 * if applicable.	 */	if (tf->flags & ATA_TFLAG_LBA48) {		desc[2] |= 0x01;		desc[4] = tf->hob_nsect;		desc[6] = tf->hob_lbal;		desc[8] = tf->hob_lbam;		desc[10] = tf->hob_lbah;	}}/** *	ata_gen_ata_sense - generate a SCSI fixed sense block *	@qc: Command that we are erroring out * *	Generate sense block for a failed ATA command @qc.  Descriptor *	format is used to accomodate LBA48 block address. * *	LOCKING: *	None. */static void ata_gen_ata_sense(struct ata_queued_cmd *qc){	struct ata_device *dev = qc->dev;	struct scsi_cmnd *cmd = qc->scsicmd;	struct ata_taskfile *tf = &qc->result_tf;	unsigned char *sb = cmd->sense_buffer;	unsigned char *desc = sb + 8;	int verbose = qc->ap->ops->error_handler == NULL;	u64 block;	memset(sb, 0, SCSI_SENSE_BUFFERSIZE);	cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;	/* sense data is current and format is descriptor */	sb[0] = 0x72;	/* Use ata_to_sense_error() to map status register bits	 * onto sense key, asc & ascq.	 */	if (qc->err_mask ||	    tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) {		ata_to_sense_error(qc->ap->print_id, tf->command, tf->feature,				   &sb[1], &sb[2], &sb[3], verbose);		sb[1] &= 0x0f;	}	block = ata_tf_read_block(&qc->result_tf, dev);	/* information sense data descriptor */	sb[7] = 12;	desc[0] = 0x00;	desc[1] = 10;	desc[2] |= 0x80;	/* valid */	desc[6] = block >> 40;	desc[7] = block >> 32;	desc[8] = block >> 24;	desc[9] = block >> 16;	desc[10] = block >> 8;	desc[11] = block;}static void ata_scsi_sdev_config(struct scsi_device *sdev){	sdev->use_10_for_rw = 1;	sdev->use_10_for_ms = 1;	/* Schedule policy is determined by ->qc_defer() callback and	 * it needs to see every deferred qc.  Set dev_blocked to 1 to	 * prevent SCSI midlayer from automatically deferring	 * requests.	 */	sdev->max_device_blocked = 1;}static void ata_scsi_dev_config(struct scsi_device *sdev,				struct ata_device *dev){	/* configure max sectors */	blk_queue_max_sectors(sdev->request_queue, dev->max_sectors);	/* SATA DMA transfers must be multiples of 4 byte, so	 * we need to pad ATAPI transfers using an extra sg.	 * Decrement max hw segments accordingly.	 */	if (dev->class == ATA_DEV_ATAPI) {		struct request_queue *q = sdev->request_queue;		blk_queue_max_hw_segments(q, q->max_hw_segments - 1);	}	if (dev->class == ATA_DEV_ATA)		sdev->manage_start_stop = 1;	if (dev->flags & ATA_DFLAG_AN)		set_bit(SDEV_EVT_MEDIA_CHANGE, sdev->supported_events);	if (dev->flags & ATA_DFLAG_NCQ) {		int depth;		depth = min(sdev->host->can_queue, ata_id_queue_depth(dev->id));		depth = min(ATA_MAX_QUEUE - 1, depth);		scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth);	}}/** *	ata_scsi_slave_config - Set SCSI device attributes *	@sdev: SCSI device to examine * *	This is called before we actually start reading *	and writing to the device, to configure certain *	SCSI mid-layer behaviors. * *	LOCKING: *	Defined by SCSI layer.  We don't really care. */int ata_scsi_slave_config(struct scsi_device *sdev){	struct ata_port *ap = ata_shost_to_port(sdev->host);	struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);	ata_scsi_sdev_config(sdev);	if (dev)		ata_scsi_dev_config(sdev, dev);	return 0;	/* scsi layer doesn't check return value, sigh */}/** *	ata_scsi_slave_destroy - SCSI device is about to be destroyed *	@sdev: SCSI device to be destroyed * *	@sdev is about to be destroyed for hot/warm unplugging.  If *	this unplugging was initiated by libata as indicated by NULL *	dev->sdev, this function doesn't have to do anything. *	Otherwise, SCSI layer initiated warm-unplug is in progress. *	Clear dev->sdev, schedule the device for ATA detach and invoke *	EH. * *	LOCKING: *	Defined by SCSI layer.  We don't really care. */void ata_scsi_slave_destroy(struct scsi_device *sdev){	struct ata_port *ap = ata_shost_to_port(sdev->host);	unsigned long flags;	struct ata_device *dev;	if (!ap->ops->error_handler)		return;	spin_lock_irqsave(ap->lock, flags);	dev = __ata_scsi_find_dev(ap, sdev);	if (dev && dev->sdev) {		/* SCSI device already in CANCEL state, no need to offline it */		dev->sdev = NULL;		dev->flags |= ATA_DFLAG_DETACH;		ata_port_schedule_eh(ap);	}	spin_unlock_irqrestore(ap->lock, flags);}/** *	ata_scsi_change_queue_depth - SCSI callback for queue depth config *	@sdev: SCSI device to configure queue depth for *	@queue_depth: new queue depth * *	This is libata standard hostt->change_queue_depth callback. *	SCSI will call into this callback when user tries to set queue *	depth via sysfs. * *	LOCKING: *	SCSI layer (we don't care) * *	RETURNS: *	Newly configured queue depth. */int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth){	struct ata_port *ap = ata_shost_to_port(sdev->host);	struct ata_device *dev;	unsigned long flags;	if (queue_depth < 1 || queue_depth == sdev->queue_depth)		return sdev->queue_depth;	dev = ata_scsi_find_dev(ap, sdev);	if (!dev || !ata_dev_enabled(dev))		return sdev->queue_depth;	/* NCQ enabled? */	spin_lock_irqsave(ap->lock, flags);	dev->flags &= ~ATA_DFLAG_NCQ_OFF;	if (queue_depth == 1 || !ata_ncq_enabled(dev)) {		dev->flags |= ATA_DFLAG_NCQ_OFF;		queue_depth = 1;	}	spin_unlock_irqrestore(ap->lock, flags);	/* limit and apply queue depth */	queue_depth = min(queue_depth, sdev->host->can_queue);	queue_depth = min(queue_depth, ata_id_queue_depth(dev->id));	queue_depth = min(queue_depth, ATA_MAX_QUEUE - 1);	if (sdev->queue_depth == queue_depth)		return -EINVAL;	scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, queue_depth);	return queue_depth;}/* XXX: for spindown warning */static void ata_delayed_done_timerfn(unsigned long arg){	struct scsi_cmnd *scmd = (void *)arg;	scmd->scsi_done(scmd);}/* XXX: for spindown warning */static void ata_delayed_done(struct scsi_cmnd *scmd){	static struct timer_list timer;	setup_timer(&timer, ata_delayed_done_timerfn, (unsigned long)scmd);	mod_timer(&timer, jiffies + 5 * HZ);}/** *	ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command *	@qc: Storage for translated ATA taskfile * *	Sets up an ATA taskfile to issue STANDBY (to stop) or READ VERIFY *	(to start). Perhaps these commands should be preceded by *	CHECK POWER MODE to see what power mode the device is already in. *	[See SAT revision 5 at www.t10.org] * *	LOCKING: *	spin_lock_irqsave(host lock) * *	RETURNS: *	Zero on success, non-zero on error. */static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -