欢迎来到虫虫下载站 | 资源下载 资源专辑 关于我们
虫虫下载站

stex.c

linux 内核源代码
C
第 1 页 / 共 3 页
字号:
	readl(base + IMR0);	writel(0, base + OMR0);	readl(base + OMR0);	writel(0, base + IMR1);	readl(base + IMR1);	writel(0, base + OMR1);	readl(base + OMR1); /* flush */	hba->mu_status = MU_STATE_STARTED;	return 0;}static int stex_abort(struct scsi_cmnd *cmd){	struct Scsi_Host *host = cmd->device->host;	struct st_hba *hba = (struct st_hba *)host->hostdata;	u16 tag = cmd->request->tag;	void __iomem *base;	u32 data;	int result = SUCCESS;	unsigned long flags;	printk(KERN_INFO DRV_NAME		"(%s): aborting command\n", pci_name(hba->pdev));	scsi_print_command(cmd);	base = hba->mmio_base;	spin_lock_irqsave(host->host_lock, flags);	if (tag < host->can_queue && hba->ccb[tag].cmd == cmd)		hba->wait_ccb = &hba->ccb[tag];	else {		for (tag = 0; tag < host->can_queue; tag++)			if (hba->ccb[tag].cmd == cmd) {				hba->wait_ccb = &hba->ccb[tag];				break;			}		if (tag >= host->can_queue)			goto out;	}	data = readl(base + ODBL);	if (data == 0 || data == 0xffffffff)		goto fail_out;	writel(data, base + ODBL);	readl(base + ODBL); /* flush */	stex_mu_intr(hba, data);	if (hba->wait_ccb == NULL) {		printk(KERN_WARNING DRV_NAME			"(%s): lost interrupt\n", pci_name(hba->pdev));		goto out;	}fail_out:	scsi_dma_unmap(cmd);	hba->wait_ccb->req = NULL; /* nullify the req's future return */	hba->wait_ccb = NULL;	result = FAILED;out:	spin_unlock_irqrestore(host->host_lock, flags);	return result;}static void stex_hard_reset(struct st_hba *hba){	struct pci_bus *bus;	int i;	u16 pci_cmd;	u8 pci_bctl;	for (i = 0; i < 16; i++)		pci_read_config_dword(hba->pdev, i * 4,			&hba->pdev->saved_config_space[i]);	/* Reset secondary bus. Our controller(MU/ATU) is the only device on	   secondary bus. Consult Intel 80331/3 developer's manual for detail */	bus = hba->pdev->bus;	pci_read_config_byte(bus->self, PCI_BRIDGE_CONTROL, &pci_bctl);	pci_bctl |= PCI_BRIDGE_CTL_BUS_RESET;	pci_write_config_byte(bus->self, PCI_BRIDGE_CONTROL, pci_bctl);	/*	 * 1 ms may be enough for 8-port controllers. But 16-port controllers	 * require more time to finish bus reset. Use 100 ms here for safety	 */	msleep(100);	pci_bctl &= ~PCI_BRIDGE_CTL_BUS_RESET;	pci_write_config_byte(bus->self, PCI_BRIDGE_CONTROL, pci_bctl);	for (i = 0; i < MU_HARD_RESET_WAIT; i++) {		pci_read_config_word(hba->pdev, PCI_COMMAND, &pci_cmd);		if (pci_cmd != 0xffff && (pci_cmd & PCI_COMMAND_MASTER))			break;		msleep(1);	}	ssleep(5);	for (i = 0; i < 16; i++)		pci_write_config_dword(hba->pdev, i * 4,			hba->pdev->saved_config_space[i]);}static int stex_reset(struct scsi_cmnd *cmd){	struct st_hba *hba;	unsigned long flags;	unsigned long before;	hba = (struct st_hba *) &cmd->device->host->hostdata[0];	printk(KERN_INFO DRV_NAME		"(%s): resetting host\n", pci_name(hba->pdev));	scsi_print_command(cmd);	hba->mu_status = MU_STATE_RESETTING;	if (hba->cardtype == st_shasta)		stex_hard_reset(hba);	if (hba->cardtype != st_yosemite) {		if (stex_handshake(hba)) {			printk(KERN_WARNING DRV_NAME				"(%s): resetting: handshake failed\n",				pci_name(hba->pdev));			return FAILED;		}		spin_lock_irqsave(hba->host->host_lock, flags);		hba->req_head = 0;		hba->req_tail = 0;		hba->status_head = 0;		hba->status_tail = 0;		hba->out_req_cnt = 0;		spin_unlock_irqrestore(hba->host->host_lock, flags);		return SUCCESS;	}	/* st_yosemite */	writel(MU_INBOUND_DOORBELL_RESET, hba->mmio_base + IDBL);	readl(hba->mmio_base + IDBL); /* flush */	before = jiffies;	while (hba->out_req_cnt > 0) {		if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ)) {			printk(KERN_WARNING DRV_NAME				"(%s): reset timeout\n", pci_name(hba->pdev));			return FAILED;		}		msleep(1);	}	hba->mu_status = MU_STATE_STARTED;	return SUCCESS;}static int stex_biosparam(struct scsi_device *sdev,	struct block_device *bdev, sector_t capacity, int geom[]){	int heads = 255, sectors = 63;	if (capacity < 0x200000) {		heads = 64;		sectors = 32;	}	sector_div(capacity, heads * sectors);	geom[0] = heads;	geom[1] = sectors;	geom[2] = capacity;	return 0;}static struct scsi_host_template driver_template = {	.module				= THIS_MODULE,	.name				= DRV_NAME,	.proc_name			= DRV_NAME,	.bios_param			= stex_biosparam,	.queuecommand			= stex_queuecommand,	.slave_alloc			= stex_slave_alloc,	.slave_configure		= stex_slave_config,	.slave_destroy			= stex_slave_destroy,	.eh_abort_handler		= stex_abort,	.eh_host_reset_handler		= stex_reset,	.can_queue			= ST_CAN_QUEUE,	.this_id			= -1,	.sg_tablesize			= ST_MAX_SG,	.cmd_per_lun			= ST_CMD_PER_LUN,	.use_sg_chaining		= ENABLE_SG_CHAINING,};static int stex_set_dma_mask(struct pci_dev * pdev){	int ret;	if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)		&& !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))		return 0;	ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK);	if (!ret)		ret = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);	return ret;}static int __devinitstex_probe(struct pci_dev *pdev, const struct pci_device_id *id){	struct st_hba *hba;	struct Scsi_Host *host;	int err;	err = pci_enable_device(pdev);	if (err)		return err;	pci_set_master(pdev);	host = scsi_host_alloc(&driver_template, sizeof(struct st_hba));	if (!host) {		printk(KERN_ERR DRV_NAME "(%s): scsi_host_alloc failed\n",			pci_name(pdev));		err = -ENOMEM;		goto out_disable;	}	hba = (struct st_hba *)host->hostdata;	memset(hba, 0, sizeof(struct st_hba));	err = pci_request_regions(pdev, DRV_NAME);	if (err < 0) {		printk(KERN_ERR DRV_NAME "(%s): request regions failed\n",			pci_name(pdev));		goto out_scsi_host_put;	}	hba->mmio_base = ioremap_nocache(pci_resource_start(pdev, 0),		pci_resource_len(pdev, 0));	if ( !hba->mmio_base) {		printk(KERN_ERR DRV_NAME "(%s): memory map failed\n",			pci_name(pdev));		err = -ENOMEM;		goto out_release_regions;	}	err = stex_set_dma_mask(pdev);	if (err) {		printk(KERN_ERR DRV_NAME "(%s): set dma mask failed\n",			pci_name(pdev));		goto out_iounmap;	}	hba->cardtype = (unsigned int) id->driver_data;	if (hba->cardtype == st_vsc && (pdev->subsystem_device & 0xf) == 0x1)		hba->cardtype = st_vsc1;	hba->dma_size = (hba->cardtype == st_vsc1) ?		(STEX_BUFFER_SIZE + ST_ADDITIONAL_MEM) : (STEX_BUFFER_SIZE);	hba->dma_mem = dma_alloc_coherent(&pdev->dev,		hba->dma_size, &hba->dma_handle, GFP_KERNEL);	if (!hba->dma_mem) {		err = -ENOMEM;		printk(KERN_ERR DRV_NAME "(%s): dma mem alloc failed\n",			pci_name(pdev));		goto out_iounmap;	}	hba->status_buffer =		(struct status_msg *)(hba->dma_mem + MU_REQ_BUFFER_SIZE);	hba->copy_buffer = hba->dma_mem + MU_BUFFER_SIZE;	hba->mu_status = MU_STATE_STARTING;	if (hba->cardtype == st_shasta) {		host->max_lun = 8;		host->max_id = 16 + 1;	} else if (hba->cardtype == st_yosemite) {		host->max_lun = 128;		host->max_id = 1 + 1;	} else {		/* st_vsc and st_vsc1 */		host->max_lun = 1;		host->max_id = 128 + 1;	}	host->max_channel = 0;	host->unique_id = host->host_no;	host->max_cmd_len = STEX_CDB_LENGTH;	hba->host = host;	hba->pdev = pdev;	init_waitqueue_head(&hba->waitq);	err = request_irq(pdev->irq, stex_intr, IRQF_SHARED, DRV_NAME, hba);	if (err) {		printk(KERN_ERR DRV_NAME "(%s): request irq failed\n",			pci_name(pdev));		goto out_pci_free;	}	err = stex_handshake(hba);	if (err)		goto out_free_irq;	err = scsi_init_shared_tag_map(host, host->can_queue);	if (err) {		printk(KERN_ERR DRV_NAME "(%s): init shared queue failed\n",			pci_name(pdev));		goto out_free_irq;	}	pci_set_drvdata(pdev, hba);	err = scsi_add_host(host, &pdev->dev);	if (err) {		printk(KERN_ERR DRV_NAME "(%s): scsi_add_host failed\n",			pci_name(pdev));		goto out_free_irq;	}	scsi_scan_host(host);	return 0;out_free_irq:	free_irq(pdev->irq, hba);out_pci_free:	dma_free_coherent(&pdev->dev, hba->dma_size,			  hba->dma_mem, hba->dma_handle);out_iounmap:	iounmap(hba->mmio_base);out_release_regions:	pci_release_regions(pdev);out_scsi_host_put:	scsi_host_put(host);out_disable:	pci_disable_device(pdev);	return err;}static void stex_hba_stop(struct st_hba *hba){	struct req_msg *req;	unsigned long flags;	unsigned long before;	u16 tag = 0;	spin_lock_irqsave(hba->host->host_lock, flags);	req = stex_alloc_req(hba);	memset(req->cdb, 0, STEX_CDB_LENGTH);	if (hba->cardtype == st_yosemite) {		req->cdb[0] = MGT_CMD;		req->cdb[1] = MGT_CMD_SIGNATURE;		req->cdb[2] = CTLR_CONFIG_CMD;		req->cdb[3] = CTLR_SHUTDOWN;	} else {		req->cdb[0] = CONTROLLER_CMD;		req->cdb[1] = CTLR_POWER_STATE_CHANGE;		req->cdb[2] = CTLR_POWER_SAVING;	}	hba->ccb[tag].cmd = NULL;	hba->ccb[tag].sg_count = 0;	hba->ccb[tag].sense_bufflen = 0;	hba->ccb[tag].sense_buffer = NULL;	hba->ccb[tag].req_type |= PASSTHRU_REQ_TYPE;	stex_send_cmd(hba, req, tag);	spin_unlock_irqrestore(hba->host->host_lock, flags);	before = jiffies;	while (hba->ccb[tag].req_type & PASSTHRU_REQ_TYPE) {		if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ))			return;		msleep(10);	}}static void stex_hba_free(struct st_hba *hba){	free_irq(hba->pdev->irq, hba);	iounmap(hba->mmio_base);	pci_release_regions(hba->pdev);	dma_free_coherent(&hba->pdev->dev, hba->dma_size,			  hba->dma_mem, hba->dma_handle);}static void stex_remove(struct pci_dev *pdev){	struct st_hba *hba = pci_get_drvdata(pdev);	scsi_remove_host(hba->host);	pci_set_drvdata(pdev, NULL);	stex_hba_stop(hba);	stex_hba_free(hba);	scsi_host_put(hba->host);	pci_disable_device(pdev);}static void stex_shutdown(struct pci_dev *pdev){	struct st_hba *hba = pci_get_drvdata(pdev);	stex_hba_stop(hba);}static struct pci_device_id stex_pci_tbl[] = {	/* st_shasta */	{ 0x105a, 0x8350, PCI_ANY_ID, PCI_ANY_ID, 0, 0,		st_shasta }, /* SuperTrak EX8350/8300/16350/16300 */	{ 0x105a, 0xc350, PCI_ANY_ID, PCI_ANY_ID, 0, 0,		st_shasta }, /* SuperTrak EX12350 */	{ 0x105a, 0x4302, PCI_ANY_ID, PCI_ANY_ID, 0, 0,		st_shasta }, /* SuperTrak EX4350 */	{ 0x105a, 0xe350, PCI_ANY_ID, PCI_ANY_ID, 0, 0,		st_shasta }, /* SuperTrak EX24350 */	/* st_vsc */	{ 0x105a, 0x7250, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_vsc },	/* st_yosemite */	{ 0x105a, 0x8650, PCI_ANY_ID, 0x4600, 0, 0,		st_yosemite }, /* SuperTrak EX4650 */	{ 0x105a, 0x8650, PCI_ANY_ID, 0x4610, 0, 0,		st_yosemite }, /* SuperTrak EX4650o */	{ 0x105a, 0x8650, PCI_ANY_ID, 0x8600, 0, 0,		st_yosemite }, /* SuperTrak EX8650EL */	{ 0x105a, 0x8650, PCI_ANY_ID, 0x8601, 0, 0,		st_yosemite }, /* SuperTrak EX8650 */	{ 0x105a, 0x8650, PCI_ANY_ID, 0x8602, 0, 0,		st_yosemite }, /* SuperTrak EX8654 */	{ 0x105a, 0x8650, PCI_ANY_ID, PCI_ANY_ID, 0, 0,		st_yosemite }, /* generic st_yosemite */	{ }	/* terminate list */};MODULE_DEVICE_TABLE(pci, stex_pci_tbl);static struct pci_driver stex_pci_driver = {	.name		= DRV_NAME,	.id_table	= stex_pci_tbl,	.probe		= stex_probe,	.remove		= __devexit_p(stex_remove),	.shutdown	= stex_shutdown,};static int __init stex_init(void){	printk(KERN_INFO DRV_NAME		": Promise SuperTrak EX Driver version: %s\n",		 ST_DRIVER_VERSION);	return pci_register_driver(&stex_pci_driver);}static void __exit stex_exit(void){	pci_unregister_driver(&stex_pci_driver);}module_init(stex_init);module_exit(stex_exit);

⌨️ 快捷键说明

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