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

📄 libata-scsi.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
 *	@ptr_io: (input/output) Location to store more output data *	@last: End of output data buffer * *	Generate a generic MODE SENSE r/w error recovery page. * *	LOCKING: *	None. */static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last){	ata_msense_push(ptr_io, last, def_rw_recovery_mpage,			sizeof(def_rw_recovery_mpage));	return sizeof(def_rw_recovery_mpage);}/* * We can turn this into a real blacklist if it's needed, for now just * blacklist any Maxtor BANC1G10 revision firmware */static int ata_dev_supports_fua(u16 *id){	unsigned char model[ATA_ID_PROD_LEN + 1], fw[ATA_ID_FW_REV_LEN + 1];	if (!libata_fua)		return 0;	if (!ata_id_has_fua(id))		return 0;	ata_id_c_string(id, model, ATA_ID_PROD, sizeof(model));	ata_id_c_string(id, fw, ATA_ID_FW_REV, sizeof(fw));	if (strcmp(model, "Maxtor"))		return 1;	if (strcmp(fw, "BANC1G10"))		return 1;	return 0; /* blacklisted */}/** *	ata_scsiop_mode_sense - Simulate MODE SENSE 6, 10 commands *	@args: device IDENTIFY data / SCSI command of interest. *	@rbuf: Response buffer, to which simulated SCSI cmd output is sent. *	@buflen: Response buffer length. * *	Simulate MODE SENSE commands. Assume this is invoked for direct *	access devices (e.g. disks) only. There should be no block *	descriptor for other device types. * *	LOCKING: *	spin_lock_irqsave(host lock) */unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,				  unsigned int buflen){	struct ata_device *dev = args->dev;	u8 *scsicmd = args->cmd->cmnd, *p, *last;	const u8 sat_blk_desc[] = {		0, 0, 0, 0,	/* number of blocks: sat unspecified */		0,		0, 0x2, 0x0	/* block length: 512 bytes */	};	u8 pg, spg;	unsigned int ebd, page_control, six_byte, output_len, alloc_len, minlen;	u8 dpofua;	VPRINTK("ENTER\n");	six_byte = (scsicmd[0] == MODE_SENSE);	ebd = !(scsicmd[1] & 0x8);      /* dbd bit inverted == edb */	/*	 * LLBA bit in msense(10) ignored (compliant)	 */	page_control = scsicmd[2] >> 6;	switch (page_control) {	case 0: /* current */		break;  /* supported */	case 3: /* saved */		goto saving_not_supp;	case 1: /* changeable */	case 2: /* defaults */	default:		goto invalid_fld;	}	if (six_byte) {		output_len = 4 + (ebd ? 8 : 0);		alloc_len = scsicmd[4];	} else {		output_len = 8 + (ebd ? 8 : 0);		alloc_len = (scsicmd[7] << 8) + scsicmd[8];	}	minlen = (alloc_len < buflen) ? alloc_len : buflen;	p = rbuf + output_len;	last = rbuf + minlen - 1;	pg = scsicmd[2] & 0x3f;	spg = scsicmd[3];	/*	 * No mode subpages supported (yet) but asking for _all_	 * subpages may be valid	 */	if (spg && (spg != ALL_SUB_MPAGES))		goto invalid_fld;	switch(pg) {	case RW_RECOVERY_MPAGE:		output_len += ata_msense_rw_recovery(&p, last);		break;	case CACHE_MPAGE:		output_len += ata_msense_caching(args->id, &p, last);		break;	case CONTROL_MPAGE: {		output_len += ata_msense_ctl_mode(&p, last);		break;		}	case ALL_MPAGES:		output_len += ata_msense_rw_recovery(&p, last);		output_len += ata_msense_caching(args->id, &p, last);		output_len += ata_msense_ctl_mode(&p, last);		break;	default:		/* invalid page code */		goto invalid_fld;	}	if (minlen < 1)		return 0;	dpofua = 0;	if (ata_dev_supports_fua(args->id) && (dev->flags & ATA_DFLAG_LBA48) &&	    (!(dev->flags & ATA_DFLAG_PIO) || dev->multi_count))		dpofua = 1 << 4;	if (six_byte) {		output_len--;		rbuf[0] = output_len;		if (minlen > 2)			rbuf[2] |= dpofua;		if (ebd) {			if (minlen > 3)				rbuf[3] = sizeof(sat_blk_desc);			if (minlen > 11)				memcpy(rbuf + 4, sat_blk_desc,				       sizeof(sat_blk_desc));		}	} else {		output_len -= 2;		rbuf[0] = output_len >> 8;		if (minlen > 1)			rbuf[1] = output_len;		if (minlen > 3)			rbuf[3] |= dpofua;		if (ebd) {			if (minlen > 7)				rbuf[7] = sizeof(sat_blk_desc);			if (minlen > 15)				memcpy(rbuf + 8, sat_blk_desc,				       sizeof(sat_blk_desc));		}	}	return 0;invalid_fld:	ata_scsi_set_sense(args->cmd, ILLEGAL_REQUEST, 0x24, 0x0);	/* "Invalid field in cbd" */	return 1;saving_not_supp:	ata_scsi_set_sense(args->cmd, ILLEGAL_REQUEST, 0x39, 0x0);	 /* "Saving parameters not supported" */	return 1;}/** *	ata_scsiop_read_cap - Simulate READ CAPACITY[ 16] commands *	@args: device IDENTIFY data / SCSI command of interest. *	@rbuf: Response buffer, to which simulated SCSI cmd output is sent. *	@buflen: Response buffer length. * *	Simulate READ CAPACITY commands. * *	LOCKING: *	None. */unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,				 unsigned int buflen){	u64 last_lba = args->dev->n_sectors - 1; /* LBA of the last block */	VPRINTK("ENTER\n");	if (args->cmd->cmnd[0] == READ_CAPACITY) {		if (last_lba >= 0xffffffffULL)			last_lba = 0xffffffff;		/* sector count, 32-bit */		ATA_SCSI_RBUF_SET(0, last_lba >> (8 * 3));		ATA_SCSI_RBUF_SET(1, last_lba >> (8 * 2));		ATA_SCSI_RBUF_SET(2, last_lba >> (8 * 1));		ATA_SCSI_RBUF_SET(3, last_lba);		/* sector size */		ATA_SCSI_RBUF_SET(6, ATA_SECT_SIZE >> 8);		ATA_SCSI_RBUF_SET(7, ATA_SECT_SIZE);	} else {		/* sector count, 64-bit */		ATA_SCSI_RBUF_SET(0, last_lba >> (8 * 7));		ATA_SCSI_RBUF_SET(1, last_lba >> (8 * 6));		ATA_SCSI_RBUF_SET(2, last_lba >> (8 * 5));		ATA_SCSI_RBUF_SET(3, last_lba >> (8 * 4));		ATA_SCSI_RBUF_SET(4, last_lba >> (8 * 3));		ATA_SCSI_RBUF_SET(5, last_lba >> (8 * 2));		ATA_SCSI_RBUF_SET(6, last_lba >> (8 * 1));		ATA_SCSI_RBUF_SET(7, last_lba);		/* sector size */		ATA_SCSI_RBUF_SET(10, ATA_SECT_SIZE >> 8);		ATA_SCSI_RBUF_SET(11, ATA_SECT_SIZE);	}	return 0;}/** *	ata_scsiop_report_luns - Simulate REPORT LUNS command *	@args: device IDENTIFY data / SCSI command of interest. *	@rbuf: Response buffer, to which simulated SCSI cmd output is sent. *	@buflen: Response buffer length. * *	Simulate REPORT LUNS command. * *	LOCKING: *	spin_lock_irqsave(host lock) */unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf,				   unsigned int buflen){	VPRINTK("ENTER\n");	rbuf[3] = 8;	/* just one lun, LUN 0, size 8 bytes */	return 0;}/** *	ata_scsi_set_sense - Set SCSI sense data and status *	@cmd: SCSI request to be handled *	@sk: SCSI-defined sense key *	@asc: SCSI-defined additional sense code *	@ascq: SCSI-defined additional sense code qualifier * *	Helper function that builds a valid fixed format, current *	response code and the given sense key (sk), additional sense *	code (asc) and additional sense code qualifier (ascq) with *	a SCSI command status of %SAM_STAT_CHECK_CONDITION and *	DRIVER_SENSE set in the upper bits of scsi_cmnd::result . * *	LOCKING: *	Not required */void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq){	cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;	cmd->sense_buffer[0] = 0x70;	/* fixed format, current */	cmd->sense_buffer[2] = sk;	cmd->sense_buffer[7] = 18 - 8;	/* additional sense length */	cmd->sense_buffer[12] = asc;	cmd->sense_buffer[13] = ascq;}/** *	ata_scsi_badcmd - End a SCSI request with an error *	@cmd: SCSI request to be handled *	@done: SCSI command completion function *	@asc: SCSI-defined additional sense code *	@ascq: SCSI-defined additional sense code qualifier * *	Helper function that completes a SCSI command with *	%SAM_STAT_CHECK_CONDITION, with a sense key %ILLEGAL_REQUEST *	and the specified additional sense codes. * *	LOCKING: *	spin_lock_irqsave(host lock) */void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 asc, u8 ascq){	DPRINTK("ENTER\n");	ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, asc, ascq);	done(cmd);}static void atapi_sense_complete(struct ata_queued_cmd *qc){	if (qc->err_mask && ((qc->err_mask & AC_ERR_DEV) == 0)) {		/* FIXME: not quite right; we don't want the		 * translation of taskfile registers into		 * a sense descriptors, since that's only		 * correct for ATA, not ATAPI		 */		ata_gen_passthru_sense(qc);	}	qc->scsidone(qc->scsicmd);	ata_qc_free(qc);}/* is it pointless to prefer PIO for "safety reasons"? */static inline int ata_pio_use_silly(struct ata_port *ap){	return (ap->flags & ATA_FLAG_PIO_DMA);}static void atapi_request_sense(struct ata_queued_cmd *qc){	struct ata_port *ap = qc->ap;	struct scsi_cmnd *cmd = qc->scsicmd;	DPRINTK("ATAPI request sense\n");	/* FIXME: is this needed? */	memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));	ap->ops->tf_read(ap, &qc->tf);	/* fill these in, for the case where they are -not- overwritten */	cmd->sense_buffer[0] = 0x70;	cmd->sense_buffer[2] = qc->tf.feature >> 4;	ata_qc_reinit(qc);	ata_sg_init_one(qc, cmd->sense_buffer, sizeof(cmd->sense_buffer));	qc->dma_dir = DMA_FROM_DEVICE;	memset(&qc->cdb, 0, qc->dev->cdb_len);	qc->cdb[0] = REQUEST_SENSE;	qc->cdb[4] = SCSI_SENSE_BUFFERSIZE;	qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;	qc->tf.command = ATA_CMD_PACKET;	if (ata_pio_use_silly(ap)) {		qc->tf.protocol = ATA_PROT_ATAPI_DMA;		qc->tf.feature |= ATAPI_PKT_DMA;	} else {		qc->tf.protocol = ATA_PROT_ATAPI;		qc->tf.lbam = SCSI_SENSE_BUFFERSIZE;		qc->tf.lbah = 0;	}	qc->nbytes = SCSI_SENSE_BUFFERSIZE;	qc->complete_fn = atapi_sense_complete;	ata_qc_issue(qc);	DPRINTK("EXIT\n");}static void atapi_qc_complete(struct ata_queued_cmd *qc){	struct scsi_cmnd *cmd = qc->scsicmd;	unsigned int err_mask = qc->err_mask;	VPRINTK("ENTER, err_mask 0x%X\n", err_mask);	/* handle completion from new EH */	if (unlikely(qc->ap->ops->error_handler &&		     (err_mask || qc->flags & ATA_QCFLAG_SENSE_VALID))) {		if (!(qc->flags & ATA_QCFLAG_SENSE_VALID)) {			/* FIXME: not quite right; we don't want the			 * translation of taskfile registers into a			 * sense descriptors, since that's only			 * correct for ATA, not ATAPI			 */			ata_gen_passthru_sense(qc);		}		/* SCSI EH automatically locks door if sdev->locked is		 * set.  Sometimes door lock request continues to		 * fail, for example, when no media is present.  This		 * creates a loop - SCSI EH issues door lock which		 * fails and gets invoked again to acquire sense data		 * for the failed command.		 *		 * If door lock fails, always clear sdev->locked to		 * avoid this infinite loop.		 */		if (qc->cdb[0] == ALLOW_MEDIUM_REMOVAL)			qc->dev->sdev->locked = 0;		qc->scsicmd->result = SAM_STAT_CHECK_CONDITION;		qc->scsidone(cmd);		ata_qc_free(qc);		return;	}	/* successful completion or old EH failure path */	if (unlikely(err_mask & AC_ERR_DEV)) {		cmd->result = SAM_STAT_CHECK_CONDITION;		atapi_request_sense(qc);		return;	} else if (unlikely(err_mask)) {		/* FIXME: not quite right; we don't want the		 * translation of taskfile registers into		 * a sense descriptors, since that's only		 * correct for ATA, not ATAPI		 */		ata_gen_passthru_sense(qc);	} else {		u8 *scsicmd = cmd->cmnd;		if ((scsicmd[0] == INQUIRY) && ((scsicmd[1] & 0x03) == 0)) {			u8 *buf = NULL;			unsigned int buflen;			buflen = ata_scsi_rbuf_get(cmd, &buf);	/* ATAPI devices typically report zero for their SCSI version,	 * and sometimes deviate from the spec WRT response data	 * format.  If SCSI version is reported as zero like normal,	 * then we make the following fixups:  1) Fake MMC-5 version,	 * to indicate to the Linux scsi midlayer this is a modern	 * device.  2) Ensure response data format / ATAPI information	 * are always correct.	 */			if (buf[2] == 0) {				buf[2] = 0x5;				buf[3] = 0x32;			}			ata_scsi_rbuf_put(cmd, buf);		}		cmd->result = SAM_STAT_GOOD;	}	qc->scsidone(cmd);	ata_qc_free(qc);}/** *	atapi_xlat - Initialize PACKET taskfile *	@qc: command structure to be initialized * *	LOCKING: *	spin_lock_irqsave(host lock) * *	RETURNS: *	Zero on success, non-zero on failure. */static unsigned int atapi_xlat(struct ata_queued_cmd *qc){	struct scsi_cmnd *scmd = qc->scsicmd;	struct ata_device *dev = qc->dev;	int using_pio = (dev->flags & ATA_DFLAG_PIO);	int nodata = (scmd->sc_data_direction == DMA_NONE);	unsigned int nbytes;	memset(qc->cdb, 0, dev->cdb_len);	memcpy(qc->cdb, scmd->cmnd, scmd->cmd_len);	qc->complete_fn = atapi_qc_complete;	qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;	if (scmd->sc_data_direction == DMA_TO_DEVICE) {		qc->tf.flags |= ATA_TFLAG_WRITE;		DPRINTK("direction: write\n");	}	qc->tf.command = ATA_CMD_PACKET;	qc->nbytes = scsi_bufflen(scmd);	/* check whether ATAPI DMA is safe */	if (!using_pio && ata_check_atapi_dma(qc))		using_pio = 1;	/* Some controller variants snoop this value for Packet	 * transfers to do state machine and FIFO management.  Thus we	 * want to set it properly, and for DMA where it is	 * effectively meaningless.	 */	nbytes = min(qc->nbytes, (unsigned int)63 * 1024);	/* Most ATAPI devices which honor transfer chunk size don't	 * behave according to the spec when odd chunk size which	 * matches the transfer length is specified.  If the number of	 

⌨️ 快捷键说明

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