cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

arxescsi.c (9220B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * linux/drivers/scsi/arm/arxescsi.c
      4 *
      5 * Copyright (C) 1997-2000 Russell King, Stefan Hanske
      6 *
      7 * This driver is based on experimentation.  Hence, it may have made
      8 * assumptions about the particular card that I have available, and
      9 * may not be reliable!
     10 *
     11 * Changelog:
     12 *  30-08-1997	RMK	0.0.0	Created, READONLY version as cumana_2.c
     13 *  22-01-1998	RMK	0.0.1	Updated to 2.1.80
     14 *  15-04-1998	RMK	0.0.1	Only do PIO if FAS216 will allow it.
     15 *  11-06-1998 	SH	0.0.2   Changed to support ARXE 16-bit SCSI card
     16 *				enabled writing
     17 *  01-01-2000	SH	0.1.0   Added *real* pseudo dma writing
     18 *				(arxescsi_pseudo_dma_write)
     19 *  02-04-2000	RMK	0.1.1	Updated for new error handling code.
     20 *  22-10-2000  SH		Updated for new registering scheme.
     21 */
     22#include <linux/module.h>
     23#include <linux/blkdev.h>
     24#include <linux/kernel.h>
     25#include <linux/string.h>
     26#include <linux/ioport.h>
     27#include <linux/proc_fs.h>
     28#include <linux/unistd.h>
     29#include <linux/stat.h>
     30#include <linux/delay.h>
     31#include <linux/init.h>
     32#include <linux/interrupt.h>
     33
     34#include <asm/dma.h>
     35#include <asm/io.h>
     36#include <asm/ecard.h>
     37
     38#include <scsi/scsi.h>
     39#include <scsi/scsi_cmnd.h>
     40#include <scsi/scsi_device.h>
     41#include <scsi/scsi_eh.h>
     42#include <scsi/scsi_host.h>
     43#include <scsi/scsi_tcq.h>
     44#include "fas216.h"
     45
     46struct arxescsi_info {
     47	FAS216_Info		info;
     48	struct expansion_card	*ec;
     49	void __iomem		*base;
     50};
     51
     52#define DMADATA_OFFSET	(0x200)
     53
     54#define DMASTAT_OFFSET	(0x600)
     55#define DMASTAT_DRQ	(1 << 0)
     56
     57#define CSTATUS_IRQ	(1 << 0)
     58
     59#define VERSION "1.10 (23/01/2003 2.5.57)"
     60
     61/*
     62 * Function: int arxescsi_dma_setup(host, SCpnt, direction, min_type)
     63 * Purpose : initialises DMA/PIO
     64 * Params  : host      - host
     65 *	     SCpnt     - command
     66 *	     direction - DMA on to/off of card
     67 *	     min_type  - minimum DMA support that we must have for this transfer
     68 * Returns : 0 if we should not set CMD_WITHDMA for transfer info command
     69 */
     70static fasdmatype_t
     71arxescsi_dma_setup(struct Scsi_Host *host, struct scsi_pointer *SCp,
     72		       fasdmadir_t direction, fasdmatype_t min_type)
     73{
     74	/*
     75	 * We don't do real DMA
     76	 */
     77	return fasdma_pseudo;
     78}
     79
     80static void arxescsi_pseudo_dma_write(unsigned char *addr, void __iomem *base)
     81{
     82       __asm__ __volatile__(
     83       "               stmdb   sp!, {r0-r12}\n"
     84       "               mov     r3, %0\n"
     85       "               mov     r1, %1\n"
     86       "               add     r2, r1, #512\n"
     87       "               mov     r4, #256\n"
     88       ".loop_1:       ldmia   r3!, {r6, r8, r10, r12}\n"
     89       "               mov     r5, r6, lsl #16\n"
     90       "               mov     r7, r8, lsl #16\n"
     91       ".loop_2:       ldrb    r0, [r1, #1536]\n"
     92       "               tst     r0, #1\n"
     93       "               beq     .loop_2\n"
     94       "               stmia   r2, {r5-r8}\n\t"
     95       "               mov     r9, r10, lsl #16\n"
     96       "               mov     r11, r12, lsl #16\n"
     97       ".loop_3:       ldrb    r0, [r1, #1536]\n"
     98       "               tst     r0, #1\n"
     99       "               beq     .loop_3\n"
    100       "               stmia   r2, {r9-r12}\n"
    101       "               subs    r4, r4, #16\n"
    102       "               bne     .loop_1\n"
    103       "               ldmia   sp!, {r0-r12}\n"
    104       :
    105       : "r" (addr), "r" (base));
    106}
    107
    108/*
    109 * Function: int arxescsi_dma_pseudo(host, SCpnt, direction, transfer)
    110 * Purpose : handles pseudo DMA
    111 * Params  : host      - host
    112 *	     SCpnt     - command
    113 *	     direction - DMA on to/off of card
    114 *	     transfer  - minimum number of bytes we expect to transfer
    115 */
    116static void
    117arxescsi_dma_pseudo(struct Scsi_Host *host, struct scsi_pointer *SCp,
    118		    fasdmadir_t direction, int transfer)
    119{
    120	struct arxescsi_info *info = (struct arxescsi_info *)host->hostdata;
    121	unsigned int length, error = 0;
    122	void __iomem *base = info->info.scsi.io_base;
    123	unsigned char *addr;
    124
    125	length = SCp->this_residual;
    126	addr = SCp->ptr;
    127
    128	if (direction == DMA_OUT) {
    129		unsigned int word;
    130		while (length > 256) {
    131			if (readb(base + 0x80) & STAT_INT) {
    132				error = 1;
    133				break;
    134			}
    135			arxescsi_pseudo_dma_write(addr, base);
    136			addr += 256;
    137			length -= 256;
    138		}
    139
    140		if (!error)
    141			while (length > 0) {
    142				if (readb(base + 0x80) & STAT_INT)
    143					break;
    144	 
    145				if (!(readb(base + DMASTAT_OFFSET) & DMASTAT_DRQ))
    146					continue;
    147
    148				word = *addr | *(addr + 1) << 8;
    149
    150				writew(word, base + DMADATA_OFFSET);
    151				if (length > 1) {
    152					addr += 2;
    153					length -= 2;
    154				} else {
    155					addr += 1;
    156					length -= 1;
    157				}
    158			}
    159	}
    160	else {
    161		if (transfer && (transfer & 255)) {
    162			while (length >= 256) {
    163				if (readb(base + 0x80) & STAT_INT) {
    164					error = 1;
    165					break;
    166				}
    167	    
    168				if (!(readb(base + DMASTAT_OFFSET) & DMASTAT_DRQ))
    169					continue;
    170
    171				readsw(base + DMADATA_OFFSET, addr, 256 >> 1);
    172				addr += 256;
    173				length -= 256;
    174			}
    175		}
    176
    177		if (!(error))
    178			while (length > 0) {
    179				unsigned long word;
    180
    181				if (readb(base + 0x80) & STAT_INT)
    182					break;
    183
    184				if (!(readb(base + DMASTAT_OFFSET) & DMASTAT_DRQ))
    185					continue;
    186
    187				word = readw(base + DMADATA_OFFSET);
    188				*addr++ = word;
    189				if (--length > 0) {
    190					*addr++ = word >> 8;
    191					length --;
    192				}
    193			}
    194	}
    195}
    196
    197/*
    198 * Function: int arxescsi_dma_stop(host, SCpnt)
    199 * Purpose : stops DMA/PIO
    200 * Params  : host  - host
    201 *	     SCpnt - command
    202 */
    203static void arxescsi_dma_stop(struct Scsi_Host *host, struct scsi_pointer *SCp)
    204{
    205	/*
    206	 * no DMA to stop
    207	 */
    208}
    209
    210/*
    211 * Function: const char *arxescsi_info(struct Scsi_Host * host)
    212 * Purpose : returns a descriptive string about this interface,
    213 * Params  : host - driver host structure to return info for.
    214 * Returns : pointer to a static buffer containing null terminated string.
    215 */
    216static const char *arxescsi_info(struct Scsi_Host *host)
    217{
    218	struct arxescsi_info *info = (struct arxescsi_info *)host->hostdata;
    219	static char string[150];
    220
    221	sprintf(string, "%s (%s) in slot %d v%s",
    222		host->hostt->name, info->info.scsi.type, info->ec->slot_no,
    223		VERSION);
    224
    225	return string;
    226}
    227
    228static int
    229arxescsi_show_info(struct seq_file *m, struct Scsi_Host *host)
    230{
    231	struct arxescsi_info *info;
    232	info = (struct arxescsi_info *)host->hostdata;
    233
    234	seq_printf(m, "ARXE 16-bit SCSI driver v%s\n", VERSION);
    235	fas216_print_host(&info->info, m);
    236	fas216_print_stats(&info->info, m);
    237	fas216_print_devices(&info->info, m);
    238	return 0;
    239}
    240
    241static struct scsi_host_template arxescsi_template = {
    242	.show_info			= arxescsi_show_info,
    243	.name				= "ARXE SCSI card",
    244	.info				= arxescsi_info,
    245	.queuecommand			= fas216_noqueue_command,
    246	.eh_host_reset_handler		= fas216_eh_host_reset,
    247	.eh_bus_reset_handler		= fas216_eh_bus_reset,
    248	.eh_device_reset_handler	= fas216_eh_device_reset,
    249	.eh_abort_handler		= fas216_eh_abort,
    250	.cmd_size			= sizeof(struct fas216_cmd_priv),
    251	.can_queue			= 0,
    252	.this_id			= 7,
    253	.sg_tablesize			= SG_ALL,
    254	.dma_boundary			= PAGE_SIZE - 1,
    255	.proc_name			= "arxescsi",
    256};
    257
    258static int arxescsi_probe(struct expansion_card *ec, const struct ecard_id *id)
    259{
    260	struct Scsi_Host *host;
    261	struct arxescsi_info *info;
    262	void __iomem *base;
    263	int ret;
    264
    265	ret = ecard_request_resources(ec);
    266	if (ret)
    267		goto out;
    268
    269	base = ecardm_iomap(ec, ECARD_RES_MEMC, 0, 0);
    270	if (!base) {
    271		ret = -ENOMEM;
    272		goto out_region;
    273	}
    274
    275	host = scsi_host_alloc(&arxescsi_template, sizeof(struct arxescsi_info));
    276	if (!host) {
    277		ret = -ENOMEM;
    278		goto out_region;
    279	}
    280
    281	info = (struct arxescsi_info *)host->hostdata;
    282	info->ec = ec;
    283	info->base = base;
    284
    285	info->info.scsi.io_base		= base + 0x2000;
    286	info->info.scsi.irq		= 0;
    287	info->info.scsi.dma		= NO_DMA;
    288	info->info.scsi.io_shift	= 5;
    289	info->info.ifcfg.clockrate	= 24; /* MHz */
    290	info->info.ifcfg.select_timeout = 255;
    291	info->info.ifcfg.asyncperiod	= 200; /* ns */
    292	info->info.ifcfg.sync_max_depth	= 0;
    293	info->info.ifcfg.cntl3		= CNTL3_FASTSCSI | CNTL3_FASTCLK;
    294	info->info.ifcfg.disconnect_ok	= 0;
    295	info->info.ifcfg.wide_max_size	= 0;
    296	info->info.ifcfg.capabilities	= FASCAP_PSEUDODMA;
    297	info->info.dma.setup		= arxescsi_dma_setup;
    298	info->info.dma.pseudo		= arxescsi_dma_pseudo;
    299	info->info.dma.stop		= arxescsi_dma_stop;
    300		
    301	ec->irqaddr = base;
    302	ec->irqmask = CSTATUS_IRQ;
    303
    304	ret = fas216_init(host);
    305	if (ret)
    306		goto out_unregister;
    307
    308	ret = fas216_add(host, &ec->dev);
    309	if (ret == 0)
    310		goto out;
    311
    312	fas216_release(host);
    313 out_unregister:
    314	scsi_host_put(host);
    315 out_region:
    316	ecard_release_resources(ec);
    317 out:
    318	return ret;
    319}
    320
    321static void arxescsi_remove(struct expansion_card *ec)
    322{
    323	struct Scsi_Host *host = ecard_get_drvdata(ec);
    324
    325	ecard_set_drvdata(ec, NULL);
    326	fas216_remove(host);
    327
    328	fas216_release(host);
    329	scsi_host_put(host);
    330	ecard_release_resources(ec);
    331}
    332
    333static const struct ecard_id arxescsi_cids[] = {
    334	{ MANU_ARXE, PROD_ARXE_SCSI },
    335	{ 0xffff, 0xffff },
    336};
    337
    338static struct ecard_driver arxescsi_driver = {
    339	.probe		= arxescsi_probe,
    340	.remove		= arxescsi_remove,
    341	.id_table	= arxescsi_cids,
    342	.drv = {
    343		.name		= "arxescsi",
    344	},
    345};
    346
    347static int __init init_arxe_scsi_driver(void)
    348{
    349	return ecard_register_driver(&arxescsi_driver);
    350}
    351
    352static void __exit exit_arxe_scsi_driver(void)
    353{
    354	ecard_remove_driver(&arxescsi_driver);
    355}
    356
    357module_init(init_arxe_scsi_driver);
    358module_exit(exit_arxe_scsi_driver);
    359
    360MODULE_AUTHOR("Stefan Hanske");
    361MODULE_DESCRIPTION("ARXESCSI driver for Acorn machines");
    362MODULE_LICENSE("GPL");
    363