brintos

brintos / linux-shallow public Read only

0
0
Text · 7.7 KiB · d1a2a22 Raw
342 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Generic Generic NCR5380 driver4 *5 * Copyright 1995-2002, Russell King6 */7#include <linux/module.h>8#include <linux/ioport.h>9#include <linux/blkdev.h>10#include <linux/init.h>11 12#include <asm/ecard.h>13#include <asm/io.h>14 15#include <scsi/scsi_host.h>16 17#define priv(host)			((struct NCR5380_hostdata *)(host)->hostdata)18#define NCR5380_read(reg)		cumanascsi_read(hostdata, reg)19#define NCR5380_write(reg, value)	cumanascsi_write(hostdata, reg, value)20 21#define NCR5380_dma_xfer_len		cumanascsi_dma_xfer_len22#define NCR5380_dma_recv_setup		cumanascsi_pread23#define NCR5380_dma_send_setup		cumanascsi_pwrite24#define NCR5380_dma_residual		NCR5380_dma_residual_none25 26#define NCR5380_intr			cumanascsi_intr27#define NCR5380_queue_command		cumanascsi_queue_command28#define NCR5380_info			cumanascsi_info29 30#define NCR5380_implementation_fields	\31	unsigned ctrl32 33struct NCR5380_hostdata;34static u8 cumanascsi_read(struct NCR5380_hostdata *, unsigned int);35static void cumanascsi_write(struct NCR5380_hostdata *, unsigned int, u8);36 37#include "../NCR5380.h"38 39#define CTRL	0x16fc40#define STAT	0x200441#define L(v)	(((v)<<16)|((v) & 0x0000ffff))42#define H(v)	(((v)>>16)|((v) & 0xffff0000))43 44static inline int cumanascsi_pwrite(struct NCR5380_hostdata *hostdata,45                                    unsigned char *addr, int len)46{47  unsigned long *laddr;48  u8 __iomem *base = hostdata->io;49  u8 __iomem *dma = hostdata->pdma_io + 0x2000;50 51  if(!len) return 0;52 53  writeb(0x02, base + CTRL);54  laddr = (unsigned long *)addr;55  while(len >= 32)56  {57    unsigned int status;58    unsigned long v;59    status = readb(base + STAT);60    if(status & 0x80)61      goto end;62    if(!(status & 0x40))63      continue;64    v=*laddr++; writew(L(v), dma); writew(H(v), dma);65    v=*laddr++; writew(L(v), dma); writew(H(v), dma);66    v=*laddr++; writew(L(v), dma); writew(H(v), dma);67    v=*laddr++; writew(L(v), dma); writew(H(v), dma);68    v=*laddr++; writew(L(v), dma); writew(H(v), dma);69    v=*laddr++; writew(L(v), dma); writew(H(v), dma);70    v=*laddr++; writew(L(v), dma); writew(H(v), dma);71    v=*laddr++; writew(L(v), dma); writew(H(v), dma);72    len -= 32;73    if(len == 0)74      break;75  }76 77  addr = (unsigned char *)laddr;78  writeb(0x12, base + CTRL);79 80  while(len > 0)81  {82    unsigned int status;83    status = readb(base + STAT);84    if(status & 0x80)85      goto end;86    if(status & 0x40)87    {88      writeb(*addr++, dma);89      if(--len == 0)90        break;91    }92 93    status = readb(base + STAT);94    if(status & 0x80)95      goto end;96    if(status & 0x40)97    {98      writeb(*addr++, dma);99      if(--len == 0)100        break;101    }102  }103end:104  writeb(hostdata->ctrl | 0x40, base + CTRL);105 106	if (len)107		return -1;108	return 0;109}110 111static inline int cumanascsi_pread(struct NCR5380_hostdata *hostdata,112                                   unsigned char *addr, int len)113{114  unsigned long *laddr;115  u8 __iomem *base = hostdata->io;116  u8 __iomem *dma = hostdata->pdma_io + 0x2000;117 118  if(!len) return 0;119 120  writeb(0x00, base + CTRL);121  laddr = (unsigned long *)addr;122  while(len >= 32)123  {124    unsigned int status;125    status = readb(base + STAT);126    if(status & 0x80)127      goto end;128    if(!(status & 0x40))129      continue;130    *laddr++ = readw(dma) | (readw(dma) << 16);131    *laddr++ = readw(dma) | (readw(dma) << 16);132    *laddr++ = readw(dma) | (readw(dma) << 16);133    *laddr++ = readw(dma) | (readw(dma) << 16);134    *laddr++ = readw(dma) | (readw(dma) << 16);135    *laddr++ = readw(dma) | (readw(dma) << 16);136    *laddr++ = readw(dma) | (readw(dma) << 16);137    *laddr++ = readw(dma) | (readw(dma) << 16);138    len -= 32;139    if(len == 0)140      break;141  }142 143  addr = (unsigned char *)laddr;144  writeb(0x10, base + CTRL);145 146  while(len > 0)147  {148    unsigned int status;149    status = readb(base + STAT);150    if(status & 0x80)151      goto end;152    if(status & 0x40)153    {154      *addr++ = readb(dma);155      if(--len == 0)156        break;157    }158 159    status = readb(base + STAT);160    if(status & 0x80)161      goto end;162    if(status & 0x40)163    {164      *addr++ = readb(dma);165      if(--len == 0)166        break;167    }168  }169end:170  writeb(hostdata->ctrl | 0x40, base + CTRL);171 172	if (len)173		return -1;174	return 0;175}176 177static int cumanascsi_dma_xfer_len(struct NCR5380_hostdata *hostdata,178                                   struct scsi_cmnd *cmd)179{180	return cmd->transfersize;181}182 183static u8 cumanascsi_read(struct NCR5380_hostdata *hostdata,184                          unsigned int reg)185{186	u8 __iomem *base = hostdata->io;187	u8 val;188 189	writeb(0, base + CTRL);190 191	val = readb(base + 0x2100 + (reg << 2));192 193	hostdata->ctrl = 0x40;194	writeb(0x40, base + CTRL);195 196	return val;197}198 199static void cumanascsi_write(struct NCR5380_hostdata *hostdata,200                             unsigned int reg, u8 value)201{202	u8 __iomem *base = hostdata->io;203 204	writeb(0, base + CTRL);205 206	writeb(value, base + 0x2100 + (reg << 2));207 208	hostdata->ctrl = 0x40;209	writeb(0x40, base + CTRL);210}211 212#include "../NCR5380.c"213 214static const struct scsi_host_template cumanascsi_template = {215	.module			= THIS_MODULE,216	.name			= "Cumana 16-bit SCSI",217	.info			= cumanascsi_info,218	.queuecommand		= cumanascsi_queue_command,219	.eh_abort_handler	= NCR5380_abort,220	.eh_host_reset_handler	= NCR5380_host_reset,221	.can_queue		= 16,222	.this_id		= 7,223	.sg_tablesize		= SG_ALL,224	.cmd_per_lun		= 2,225	.proc_name		= "CumanaSCSI-1",226	.cmd_size		= sizeof(struct NCR5380_cmd),227	.max_sectors		= 128,228	.dma_boundary		= PAGE_SIZE - 1,229};230 231static int cumanascsi1_probe(struct expansion_card *ec,232			     const struct ecard_id *id)233{234	struct Scsi_Host *host;235	int ret;236 237	ret = ecard_request_resources(ec);238	if (ret)239		goto out;240 241	host = scsi_host_alloc(&cumanascsi_template, sizeof(struct NCR5380_hostdata));242	if (!host) {243		ret = -ENOMEM;244		goto out_release;245	}246 247	priv(host)->io = ioremap(ecard_resource_start(ec, ECARD_RES_IOCSLOW),248	                         ecard_resource_len(ec, ECARD_RES_IOCSLOW));249	priv(host)->pdma_io = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),250	                              ecard_resource_len(ec, ECARD_RES_MEMC));251	if (!priv(host)->io || !priv(host)->pdma_io) {252		ret = -ENOMEM;253		goto out_unmap;254	}255 256	host->irq = ec->irq;257 258	ret = NCR5380_init(host, FLAG_DMA_FIXUP | FLAG_LATE_DMA_SETUP);259	if (ret)260		goto out_unmap;261 262	NCR5380_maybe_reset_bus(host);263 264        priv(host)->ctrl = 0;265        writeb(0, priv(host)->io + CTRL);266 267	ret = request_irq(host->irq, cumanascsi_intr, 0,268			  "CumanaSCSI-1", host);269	if (ret) {270		printk("scsi%d: IRQ%d not free: %d\n",271		    host->host_no, host->irq, ret);272		goto out_exit;273	}274 275	ret = scsi_add_host(host, &ec->dev);276	if (ret)277		goto out_free_irq;278 279	scsi_scan_host(host);280	goto out;281 282 out_free_irq:283	free_irq(host->irq, host);284 out_exit:285	NCR5380_exit(host);286 out_unmap:287	iounmap(priv(host)->io);288	iounmap(priv(host)->pdma_io);289	scsi_host_put(host);290 out_release:291	ecard_release_resources(ec);292 out:293	return ret;294}295 296static void cumanascsi1_remove(struct expansion_card *ec)297{298	struct Scsi_Host *host = ecard_get_drvdata(ec);299	void __iomem *base = priv(host)->io;300	void __iomem *dma = priv(host)->pdma_io;301 302	ecard_set_drvdata(ec, NULL);303 304	scsi_remove_host(host);305	free_irq(host->irq, host);306	NCR5380_exit(host);307	scsi_host_put(host);308	iounmap(base);309	iounmap(dma);310	ecard_release_resources(ec);311}312 313static const struct ecard_id cumanascsi1_cids[] = {314	{ MANU_CUMANA, PROD_CUMANA_SCSI_1 },315	{ 0xffff, 0xffff }316};317 318static struct ecard_driver cumanascsi1_driver = {319	.probe		= cumanascsi1_probe,320	.remove		= cumanascsi1_remove,321	.id_table	= cumanascsi1_cids,322	.drv = {323		.name		= "cumanascsi1",324	},325};326 327static int __init cumanascsi_init(void)328{329	return ecard_register_driver(&cumanascsi1_driver);330}331 332static void __exit cumanascsi_exit(void)333{334	ecard_remove_driver(&cumanascsi1_driver);335}336 337module_init(cumanascsi_init);338module_exit(cumanascsi_exit);339 340MODULE_DESCRIPTION("Cumana SCSI-1 driver for Acorn machines");341MODULE_LICENSE("GPL");342