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

📄 libata-scsi.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
 *	termination. * *	LOCKING: *	spin_lock_irqsave(host lock) * *	RETURNS: *	0 on success, SCSI_ML_QUEUE_DEVICE_BUSY if the command *	needs to be deferred. */static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,			      void (*done)(struct scsi_cmnd *),			      ata_xlat_func_t xlat_func){	struct ata_port *ap = dev->link->ap;	struct ata_queued_cmd *qc;	int rc;	VPRINTK("ENTER\n");	qc = ata_scsi_qc_new(dev, cmd, done);	if (!qc)		goto err_mem;	/* data is present; dma-map it */	if (cmd->sc_data_direction == DMA_FROM_DEVICE ||	    cmd->sc_data_direction == DMA_TO_DEVICE) {		if (unlikely(scsi_bufflen(cmd) < 1)) {			ata_dev_printk(dev, KERN_WARNING,				       "WARNING: zero len r/w req\n");			goto err_did;		}		ata_sg_init(qc, scsi_sglist(cmd), scsi_sg_count(cmd));		qc->dma_dir = cmd->sc_data_direction;	}	qc->complete_fn = ata_scsi_qc_complete;	if (xlat_func(qc))		goto early_finish;	if (ap->ops->qc_defer) {		if ((rc = ap->ops->qc_defer(qc)))			goto defer;	}	/* select device, send command to hardware */	ata_qc_issue(qc);	VPRINTK("EXIT\n");	return 0;early_finish:	ata_qc_free(qc);	qc->scsidone(cmd);	DPRINTK("EXIT - early finish (good or error)\n");	return 0;err_did:	ata_qc_free(qc);	cmd->result = (DID_ERROR << 16);	qc->scsidone(cmd);err_mem:	DPRINTK("EXIT - internal\n");	return 0;defer:	ata_qc_free(qc);	DPRINTK("EXIT - defer\n");	if (rc == ATA_DEFER_LINK)		return SCSI_MLQUEUE_DEVICE_BUSY;	else		return SCSI_MLQUEUE_HOST_BUSY;}/** *	ata_scsi_rbuf_get - Map response buffer. *	@cmd: SCSI command containing buffer to be mapped. *	@buf_out: Pointer to mapped area. * *	Maps buffer contained within SCSI command @cmd. * *	LOCKING: *	spin_lock_irqsave(host lock) * *	RETURNS: *	Length of response buffer. */static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out){	u8 *buf;	unsigned int buflen;	struct scatterlist *sg = scsi_sglist(cmd);	if (sg) {		buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;		buflen = sg->length;	} else {		buf = NULL;		buflen = 0;	}	*buf_out = buf;	return buflen;}/** *	ata_scsi_rbuf_put - Unmap response buffer. *	@cmd: SCSI command containing buffer to be unmapped. *	@buf: buffer to unmap * *	Unmaps response buffer contained within @cmd. * *	LOCKING: *	spin_lock_irqsave(host lock) */static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf){	struct scatterlist *sg = scsi_sglist(cmd);	if (sg)		kunmap_atomic(buf - sg->offset, KM_IRQ0);}/** *	ata_scsi_rbuf_fill - wrapper for SCSI command simulators *	@args: device IDENTIFY data / SCSI command of interest. *	@actor: Callback hook for desired SCSI command simulator * *	Takes care of the hard work of simulating a SCSI command... *	Mapping the response buffer, calling the command's handler, *	and handling the handler's return value.  This return value *	indicates whether the handler wishes the SCSI command to be *	completed successfully (0), or not (in which case cmd->result *	and sense buffer are assumed to be set). * *	LOCKING: *	spin_lock_irqsave(host lock) */void ata_scsi_rbuf_fill(struct ata_scsi_args *args,			unsigned int (*actor) (struct ata_scsi_args *args,					       u8 *rbuf, unsigned int buflen)){	u8 *rbuf;	unsigned int buflen, rc;	struct scsi_cmnd *cmd = args->cmd;	buflen = ata_scsi_rbuf_get(cmd, &rbuf);	memset(rbuf, 0, buflen);	rc = actor(args, rbuf, buflen);	ata_scsi_rbuf_put(cmd, rbuf);	if (rc == 0)		cmd->result = SAM_STAT_GOOD;	args->done(cmd);}/** *	ATA_SCSI_RBUF_SET - helper to set values in SCSI response buffer *	@idx: byte index into SCSI response buffer *	@val: value to set * *	To be used by SCSI command simulator functions.  This macros *	expects two local variables, u8 *rbuf and unsigned int buflen, *	are in scope. * *	LOCKING: *	None. */#define ATA_SCSI_RBUF_SET(idx, val) do { \		if ((idx) < buflen) rbuf[(idx)] = (u8)(val); \	} while (0)/** *	ata_scsiop_inq_std - Simulate INQUIRY command *	@args: device IDENTIFY data / SCSI command of interest. *	@rbuf: Response buffer, to which simulated SCSI cmd output is sent. *	@buflen: Response buffer length. * *	Returns standard device identification data associated *	with non-VPD INQUIRY command output. * *	LOCKING: *	spin_lock_irqsave(host lock) */unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,			       unsigned int buflen){	u8 hdr[] = {		TYPE_DISK,		0,		0x5,	/* claim SPC-3 version compatibility */		2,		95 - 4	};	/* set scsi removeable (RMB) bit per ata bit */	if (ata_id_removeable(args->id))		hdr[1] |= (1 << 7);	VPRINTK("ENTER\n");	memcpy(rbuf, hdr, sizeof(hdr));	if (buflen > 35) {		memcpy(&rbuf[8], "ATA     ", 8);		ata_id_string(args->id, &rbuf[16], ATA_ID_PROD, 16);		ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4);		if (rbuf[32] == 0 || rbuf[32] == ' ')			memcpy(&rbuf[32], "n/a ", 4);	}	if (buflen > 63) {		const u8 versions[] = {			0x60,	/* SAM-3 (no version claimed) */			0x03,			0x20,	/* SBC-2 (no version claimed) */			0x02,			0x60	/* SPC-3 (no version claimed) */		};		memcpy(rbuf + 59, versions, sizeof(versions));	}	return 0;}/** *	ata_scsiop_inq_00 - Simulate INQUIRY VPD page 0, list of pages *	@args: device IDENTIFY data / SCSI command of interest. *	@rbuf: Response buffer, to which simulated SCSI cmd output is sent. *	@buflen: Response buffer length. * *	Returns list of inquiry VPD pages available. * *	LOCKING: *	spin_lock_irqsave(host lock) */unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf,			      unsigned int buflen){	const u8 pages[] = {		0x00,	/* page 0x00, this page */		0x80,	/* page 0x80, unit serial no page */		0x83	/* page 0x83, device ident page */	};	rbuf[3] = sizeof(pages);	/* number of supported VPD pages */	if (buflen > 6)		memcpy(rbuf + 4, pages, sizeof(pages));	return 0;}/** *	ata_scsiop_inq_80 - Simulate INQUIRY VPD page 80, device serial number *	@args: device IDENTIFY data / SCSI command of interest. *	@rbuf: Response buffer, to which simulated SCSI cmd output is sent. *	@buflen: Response buffer length. * *	Returns ATA device serial number. * *	LOCKING: *	spin_lock_irqsave(host lock) */unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,			      unsigned int buflen){	const u8 hdr[] = {		0,		0x80,			/* this page code */		0,		ATA_ID_SERNO_LEN,	/* page len */	};	memcpy(rbuf, hdr, sizeof(hdr));	if (buflen > (ATA_ID_SERNO_LEN + 4 - 1))		ata_id_string(args->id, (unsigned char *) &rbuf[4],			      ATA_ID_SERNO, ATA_ID_SERNO_LEN);	return 0;}/** *	ata_scsiop_inq_83 - Simulate INQUIRY VPD page 83, device identity *	@args: device IDENTIFY data / SCSI command of interest. *	@rbuf: Response buffer, to which simulated SCSI cmd output is sent. *	@buflen: Response buffer length. * *	Yields two logical unit device identification designators: *	 - vendor specific ASCII containing the ATA serial number *	 - SAT defined "t10 vendor id based" containing ASCII vendor *	   name ("ATA     "), model and serial numbers. * *	LOCKING: *	spin_lock_irqsave(host lock) */unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,			      unsigned int buflen){	int num;	const int sat_model_serial_desc_len = 68;	rbuf[1] = 0x83;			/* this page code */	num = 4;	if (buflen > (ATA_ID_SERNO_LEN + num + 3)) {		/* piv=0, assoc=lu, code_set=ACSII, designator=vendor */		rbuf[num + 0] = 2;		rbuf[num + 3] = ATA_ID_SERNO_LEN;		num += 4;		ata_id_string(args->id, (unsigned char *) rbuf + num,			      ATA_ID_SERNO, ATA_ID_SERNO_LEN);		num += ATA_ID_SERNO_LEN;	}	if (buflen > (sat_model_serial_desc_len + num + 3)) {		/* SAT defined lu model and serial numbers descriptor */		/* piv=0, assoc=lu, code_set=ACSII, designator=t10 vendor id */		rbuf[num + 0] = 2;		rbuf[num + 1] = 1;		rbuf[num + 3] = sat_model_serial_desc_len;		num += 4;		memcpy(rbuf + num, "ATA     ", 8);		num += 8;		ata_id_string(args->id, (unsigned char *) rbuf + num,			      ATA_ID_PROD, ATA_ID_PROD_LEN);		num += ATA_ID_PROD_LEN;		ata_id_string(args->id, (unsigned char *) rbuf + num,			      ATA_ID_SERNO, ATA_ID_SERNO_LEN);		num += ATA_ID_SERNO_LEN;	}	rbuf[3] = num - 4;    /* page len (assume less than 256 bytes) */	return 0;}/** *	ata_scsiop_inq_89 - Simulate INQUIRY VPD page 89, ATA info *	@args: device IDENTIFY data / SCSI command of interest. *	@rbuf: Response buffer, to which simulated SCSI cmd output is sent. *	@buflen: Response buffer length. * *	Yields SAT-specified ATA VPD page. * *	LOCKING: *	spin_lock_irqsave(host lock) */unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf,			      unsigned int buflen){	u8 pbuf[60];	struct ata_taskfile tf;	unsigned int i;	if (!buflen)		return 0;	memset(&pbuf, 0, sizeof(pbuf));	memset(&tf, 0, sizeof(tf));	pbuf[1] = 0x89;			/* our page code */	pbuf[2] = (0x238 >> 8);		/* page size fixed at 238h */	pbuf[3] = (0x238 & 0xff);	memcpy(&pbuf[8], "linux   ", 8);	memcpy(&pbuf[16], "libata          ", 16);	memcpy(&pbuf[32], DRV_VERSION, 4);	ata_id_string(args->id, &pbuf[32], ATA_ID_FW_REV, 4);	/* we don't store the ATA device signature, so we fake it */	tf.command = ATA_DRDY;		/* really, this is Status reg */	tf.lbal = 0x1;	tf.nsect = 0x1;	ata_tf_to_fis(&tf, 0, 1, &pbuf[36]);	/* TODO: PMP? */	pbuf[36] = 0x34;		/* force D2H Reg FIS (34h) */	pbuf[56] = ATA_CMD_ID_ATA;	i = min(buflen, 60U);	memcpy(rbuf, &pbuf[0], i);	buflen -= i;	if (!buflen)		return 0;	memcpy(&rbuf[60], &args->id[0], min(buflen, 512U));	return 0;}/** *	ata_scsiop_noop - Command handler that simply returns success. *	@args: device IDENTIFY data / SCSI command of interest. *	@rbuf: Response buffer, to which simulated SCSI cmd output is sent. *	@buflen: Response buffer length. * *	No operation.  Simply returns success to caller, to indicate *	that the caller should successfully complete this SCSI command. * *	LOCKING: *	spin_lock_irqsave(host lock) */unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf,			    unsigned int buflen){	VPRINTK("ENTER\n");	return 0;}/** *	ata_msense_push - Push data onto MODE SENSE data output buffer *	@ptr_io: (input/output) Location to store more output data *	@last: End of output data buffer *	@buf: Pointer to BLOB being added to output buffer *	@buflen: Length of BLOB * *	Store MODE SENSE data on an output buffer. * *	LOCKING: *	None. */static void ata_msense_push(u8 **ptr_io, const u8 *last,			    const u8 *buf, unsigned int buflen){	u8 *ptr = *ptr_io;	if ((ptr + buflen - 1) > last)		return;	memcpy(ptr, buf, buflen);	ptr += buflen;	*ptr_io = ptr;}/** *	ata_msense_caching - Simulate MODE SENSE caching info page *	@id: device IDENTIFY data *	@ptr_io: (input/output) Location to store more output data *	@last: End of output data buffer * *	Generate a caching info page, which conditionally indicates *	write caching to the SCSI layer, depending on device *	capabilities. * *	LOCKING: *	None. */static unsigned int ata_msense_caching(u16 *id, u8 **ptr_io,				       const u8 *last){	u8 page[CACHE_MPAGE_LEN];	memcpy(page, def_cache_mpage, sizeof(page));	if (ata_id_wcache_enabled(id))		page[2] |= (1 << 2);	/* write cache enable */	if (!ata_id_rahead_enabled(id))		page[12] |= (1 << 5);	/* disable read ahead */	ata_msense_push(ptr_io, last, page, sizeof(page));	return sizeof(page);}/** *	ata_msense_ctl_mode - Simulate MODE SENSE control mode page *	@dev: Device associated with this MODE SENSE command *	@ptr_io: (input/output) Location to store more output data *	@last: End of output data buffer * *	Generate a generic MODE SENSE control mode page. * *	LOCKING: *	None. */static unsigned int ata_msense_ctl_mode(u8 **ptr_io, const u8 *last){	ata_msense_push(ptr_io, last, def_control_mpage,			sizeof(def_control_mpage));	return sizeof(def_control_mpage);}/** *	ata_msense_rw_recovery - Simulate MODE SENSE r/w error recovery page *	@dev: Device associated with this MODE SENSE command

⌨️ 快捷键说明

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