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

mac53c94.c (15310B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * SCSI low-level driver for the 53c94 SCSI bus adaptor found
      4 * on Power Macintosh computers, controlling the external SCSI chain.
      5 * We assume the 53c94 is connected to a DBDMA (descriptor-based DMA)
      6 * controller.
      7 *
      8 * Paul Mackerras, August 1996.
      9 * Copyright (C) 1996 Paul Mackerras.
     10 */
     11#include <linux/kernel.h>
     12#include <linux/delay.h>
     13#include <linux/types.h>
     14#include <linux/string.h>
     15#include <linux/slab.h>
     16#include <linux/blkdev.h>
     17#include <linux/proc_fs.h>
     18#include <linux/stat.h>
     19#include <linux/spinlock.h>
     20#include <linux/interrupt.h>
     21#include <linux/module.h>
     22#include <linux/pci.h>
     23#include <linux/pgtable.h>
     24#include <asm/dbdma.h>
     25#include <asm/io.h>
     26#include <asm/prom.h>
     27#include <asm/macio.h>
     28
     29#include <scsi/scsi.h>
     30#include <scsi/scsi_cmnd.h>
     31#include <scsi/scsi_device.h>
     32#include <scsi/scsi_host.h>
     33
     34#include "mac53c94.h"
     35
     36enum fsc_phase {
     37	idle,
     38	selecting,
     39	dataing,
     40	completing,
     41	busfreeing,
     42};
     43
     44struct fsc_state {
     45	struct	mac53c94_regs __iomem *regs;
     46	int	intr;
     47	struct	dbdma_regs __iomem *dma;
     48	int	dmaintr;
     49	int	clk_freq;
     50	struct	Scsi_Host *host;
     51	struct scsi_cmnd *request_q;
     52	struct scsi_cmnd *request_qtail;
     53	struct scsi_cmnd *current_req;		/* req we're currently working on */
     54	enum fsc_phase phase;		/* what we're currently trying to do */
     55	struct dbdma_cmd *dma_cmds;	/* space for dbdma commands, aligned */
     56	void	*dma_cmd_space;
     57	struct	pci_dev *pdev;
     58	dma_addr_t dma_addr;
     59	struct macio_dev *mdev;
     60};
     61
     62static void mac53c94_init(struct fsc_state *);
     63static void mac53c94_start(struct fsc_state *);
     64static void mac53c94_interrupt(int, void *);
     65static irqreturn_t do_mac53c94_interrupt(int, void *);
     66static void cmd_done(struct fsc_state *, int result);
     67static void set_dma_cmds(struct fsc_state *, struct scsi_cmnd *);
     68
     69static int mac53c94_queue_lck(struct scsi_cmnd *cmd)
     70{
     71	struct fsc_state *state;
     72
     73#if 0
     74	if (cmd->sc_data_direction == DMA_TO_DEVICE) {
     75		int i;
     76		printk(KERN_DEBUG "mac53c94_queue %p: command is", cmd);
     77		for (i = 0; i < cmd->cmd_len; ++i)
     78			printk(KERN_CONT " %.2x", cmd->cmnd[i]);
     79		printk(KERN_CONT "\n");
     80		printk(KERN_DEBUG "use_sg=%d request_bufflen=%d request_buffer=%p\n",
     81		       scsi_sg_count(cmd), scsi_bufflen(cmd), scsi_sglist(cmd));
     82	}
     83#endif
     84
     85	cmd->host_scribble = NULL;
     86
     87	state = (struct fsc_state *) cmd->device->host->hostdata;
     88
     89	if (state->request_q == NULL)
     90		state->request_q = cmd;
     91	else
     92		state->request_qtail->host_scribble = (void *) cmd;
     93	state->request_qtail = cmd;
     94
     95	if (state->phase == idle)
     96		mac53c94_start(state);
     97
     98	return 0;
     99}
    100
    101static DEF_SCSI_QCMD(mac53c94_queue)
    102
    103static int mac53c94_host_reset(struct scsi_cmnd *cmd)
    104{
    105	struct fsc_state *state = (struct fsc_state *) cmd->device->host->hostdata;
    106	struct mac53c94_regs __iomem *regs = state->regs;
    107	struct dbdma_regs __iomem *dma = state->dma;
    108	unsigned long flags;
    109
    110	spin_lock_irqsave(cmd->device->host->host_lock, flags);
    111
    112	writel((RUN|PAUSE|FLUSH|WAKE) << 16, &dma->control);
    113	writeb(CMD_SCSI_RESET, &regs->command);	/* assert RST */
    114	udelay(100);			/* leave it on for a while (>= 25us) */
    115	writeb(CMD_RESET, &regs->command);
    116	udelay(20);
    117	mac53c94_init(state);
    118	writeb(CMD_NOP, &regs->command);
    119
    120	spin_unlock_irqrestore(cmd->device->host->host_lock, flags);
    121	return SUCCESS;
    122}
    123
    124static void mac53c94_init(struct fsc_state *state)
    125{
    126	struct mac53c94_regs __iomem *regs = state->regs;
    127	struct dbdma_regs __iomem *dma = state->dma;
    128
    129	writeb(state->host->this_id | CF1_PAR_ENABLE, &regs->config1);
    130	writeb(TIMO_VAL(250), &regs->sel_timeout);	/* 250ms */
    131	writeb(CLKF_VAL(state->clk_freq), &regs->clk_factor);
    132	writeb(CF2_FEATURE_EN, &regs->config2);
    133	writeb(0, &regs->config3);
    134	writeb(0, &regs->sync_period);
    135	writeb(0, &regs->sync_offset);
    136	(void)readb(&regs->interrupt);
    137	writel((RUN|PAUSE|FLUSH|WAKE) << 16, &dma->control);
    138}
    139
    140/*
    141 * Start the next command for a 53C94.
    142 * Should be called with interrupts disabled.
    143 */
    144static void mac53c94_start(struct fsc_state *state)
    145{
    146	struct scsi_cmnd *cmd;
    147	struct mac53c94_regs __iomem *regs = state->regs;
    148	int i;
    149
    150	if (state->phase != idle || state->current_req != NULL)
    151		panic("inappropriate mac53c94_start (state=%p)", state);
    152	if (state->request_q == NULL)
    153		return;
    154	state->current_req = cmd = state->request_q;
    155	state->request_q = (struct scsi_cmnd *) cmd->host_scribble;
    156
    157	/* Off we go */
    158	writeb(0, &regs->count_lo);
    159	writeb(0, &regs->count_mid);
    160	writeb(0, &regs->count_hi);
    161	writeb(CMD_NOP + CMD_DMA_MODE, &regs->command);
    162	udelay(1);
    163	writeb(CMD_FLUSH, &regs->command);
    164	udelay(1);
    165	writeb(cmd->device->id, &regs->dest_id);
    166	writeb(0, &regs->sync_period);
    167	writeb(0, &regs->sync_offset);
    168
    169	/* load the command into the FIFO */
    170	for (i = 0; i < cmd->cmd_len; ++i)
    171		writeb(cmd->cmnd[i], &regs->fifo);
    172
    173	/* do select without ATN XXX */
    174	writeb(CMD_SELECT, &regs->command);
    175	state->phase = selecting;
    176
    177	set_dma_cmds(state, cmd);
    178}
    179
    180static irqreturn_t do_mac53c94_interrupt(int irq, void *dev_id)
    181{
    182	unsigned long flags;
    183	struct Scsi_Host *dev = ((struct fsc_state *) dev_id)->current_req->device->host;
    184	
    185	spin_lock_irqsave(dev->host_lock, flags);
    186	mac53c94_interrupt(irq, dev_id);
    187	spin_unlock_irqrestore(dev->host_lock, flags);
    188	return IRQ_HANDLED;
    189}
    190
    191static void mac53c94_interrupt(int irq, void *dev_id)
    192{
    193	struct fsc_state *state = (struct fsc_state *) dev_id;
    194	struct mac53c94_regs __iomem *regs = state->regs;
    195	struct dbdma_regs __iomem *dma = state->dma;
    196	struct scsi_cmnd *const cmd = state->current_req;
    197	struct mac53c94_cmd_priv *const mcmd = mac53c94_priv(cmd);
    198	int nb, stat, seq, intr;
    199	static int mac53c94_errors;
    200
    201	/*
    202	 * Apparently, reading the interrupt register unlatches
    203	 * the status and sequence step registers.
    204	 */
    205	seq = readb(&regs->seqstep);
    206	stat = readb(&regs->status);
    207	intr = readb(&regs->interrupt);
    208
    209#if 0
    210	printk(KERN_DEBUG "mac53c94_intr, intr=%x stat=%x seq=%x phase=%d\n",
    211	       intr, stat, seq, state->phase);
    212#endif
    213
    214	if (intr & INTR_RESET) {
    215		/* SCSI bus was reset */
    216		printk(KERN_INFO "external SCSI bus reset detected\n");
    217		writeb(CMD_NOP, &regs->command);
    218		writel(RUN << 16, &dma->control);	/* stop dma */
    219		cmd_done(state, DID_RESET << 16);
    220		return;
    221	}
    222	if (intr & INTR_ILL_CMD) {
    223		printk(KERN_ERR "53c94: invalid cmd, intr=%x stat=%x seq=%x phase=%d\n",
    224		       intr, stat, seq, state->phase);
    225		cmd_done(state, DID_ERROR << 16);
    226		return;
    227	}
    228	if (stat & STAT_ERROR) {
    229#if 0
    230		/* XXX these seem to be harmless? */
    231		printk("53c94: bad error, intr=%x stat=%x seq=%x phase=%d\n",
    232		       intr, stat, seq, state->phase);
    233#endif
    234		++mac53c94_errors;
    235		writeb(CMD_NOP + CMD_DMA_MODE, &regs->command);
    236	}
    237	if (!cmd) {
    238		printk(KERN_DEBUG "53c94: interrupt with no command active?\n");
    239		return;
    240	}
    241	if (stat & STAT_PARITY) {
    242		printk(KERN_ERR "mac53c94: parity error\n");
    243		cmd_done(state, DID_PARITY << 16);
    244		return;
    245	}
    246	switch (state->phase) {
    247	case selecting:
    248		if (intr & INTR_DISCONNECT) {
    249			/* selection timed out */
    250			cmd_done(state, DID_BAD_TARGET << 16);
    251			return;
    252		}
    253		if (intr != INTR_BUS_SERV + INTR_DONE) {
    254			printk(KERN_DEBUG "got intr %x during selection\n", intr);
    255			cmd_done(state, DID_ERROR << 16);
    256			return;
    257		}
    258		if ((seq & SS_MASK) != SS_DONE) {
    259			printk(KERN_DEBUG "seq step %x after command\n", seq);
    260			cmd_done(state, DID_ERROR << 16);
    261			return;
    262		}
    263		writeb(CMD_NOP, &regs->command);
    264		/* set DMA controller going if any data to transfer */
    265		if ((stat & (STAT_MSG|STAT_CD)) == 0
    266		    && (scsi_sg_count(cmd) > 0 || scsi_bufflen(cmd))) {
    267			nb = mcmd->this_residual;
    268			if (nb > 0xfff0)
    269				nb = 0xfff0;
    270			mcmd->this_residual -= nb;
    271			writeb(nb, &regs->count_lo);
    272			writeb(nb >> 8, &regs->count_mid);
    273			writeb(CMD_DMA_MODE + CMD_NOP, &regs->command);
    274			writel(virt_to_phys(state->dma_cmds), &dma->cmdptr);
    275			writel((RUN << 16) | RUN, &dma->control);
    276			writeb(CMD_DMA_MODE + CMD_XFER_DATA, &regs->command);
    277			state->phase = dataing;
    278			break;
    279		} else if ((stat & STAT_PHASE) == STAT_CD + STAT_IO) {
    280			/* up to status phase already */
    281			writeb(CMD_I_COMPLETE, &regs->command);
    282			state->phase = completing;
    283		} else {
    284			printk(KERN_DEBUG "in unexpected phase %x after cmd\n",
    285			       stat & STAT_PHASE);
    286			cmd_done(state, DID_ERROR << 16);
    287			return;
    288		}
    289		break;
    290
    291	case dataing:
    292		if (intr != INTR_BUS_SERV) {
    293			printk(KERN_DEBUG "got intr %x before status\n", intr);
    294			cmd_done(state, DID_ERROR << 16);
    295			return;
    296		}
    297		if (mcmd->this_residual != 0
    298		    && (stat & (STAT_MSG|STAT_CD)) == 0) {
    299			/* Set up the count regs to transfer more */
    300			nb = mcmd->this_residual;
    301			if (nb > 0xfff0)
    302				nb = 0xfff0;
    303			mcmd->this_residual -= nb;
    304			writeb(nb, &regs->count_lo);
    305			writeb(nb >> 8, &regs->count_mid);
    306			writeb(CMD_DMA_MODE + CMD_NOP, &regs->command);
    307			writeb(CMD_DMA_MODE + CMD_XFER_DATA, &regs->command);
    308			break;
    309		}
    310		if ((stat & STAT_PHASE) != STAT_CD + STAT_IO) {
    311			printk(KERN_DEBUG "intr %x before data xfer complete\n", intr);
    312		}
    313		writel(RUN << 16, &dma->control);	/* stop dma */
    314		scsi_dma_unmap(cmd);
    315		/* should check dma status */
    316		writeb(CMD_I_COMPLETE, &regs->command);
    317		state->phase = completing;
    318		break;
    319	case completing:
    320		if (intr != INTR_DONE) {
    321			printk(KERN_DEBUG "got intr %x on completion\n", intr);
    322			cmd_done(state, DID_ERROR << 16);
    323			return;
    324		}
    325		mcmd->status = readb(&regs->fifo);
    326		mcmd->message = readb(&regs->fifo);
    327		writeb(CMD_ACCEPT_MSG, &regs->command);
    328		state->phase = busfreeing;
    329		break;
    330	case busfreeing:
    331		if (intr != INTR_DISCONNECT) {
    332			printk(KERN_DEBUG "got intr %x when expected disconnect\n", intr);
    333		}
    334		cmd_done(state, (DID_OK << 16) + (mcmd->message << 8) + mcmd->status);
    335		break;
    336	default:
    337		printk(KERN_DEBUG "don't know about phase %d\n", state->phase);
    338	}
    339}
    340
    341static void cmd_done(struct fsc_state *state, int result)
    342{
    343	struct scsi_cmnd *cmd;
    344
    345	cmd = state->current_req;
    346	if (cmd) {
    347		cmd->result = result;
    348		scsi_done(cmd);
    349		state->current_req = NULL;
    350	}
    351	state->phase = idle;
    352	mac53c94_start(state);
    353}
    354
    355/*
    356 * Set up DMA commands for transferring data.
    357 */
    358static void set_dma_cmds(struct fsc_state *state, struct scsi_cmnd *cmd)
    359{
    360	int i, dma_cmd, total, nseg;
    361	struct scatterlist *scl;
    362	struct dbdma_cmd *dcmds;
    363	dma_addr_t dma_addr;
    364	u32 dma_len;
    365
    366	nseg = scsi_dma_map(cmd);
    367	BUG_ON(nseg < 0);
    368	if (!nseg)
    369		return;
    370
    371	dma_cmd = cmd->sc_data_direction == DMA_TO_DEVICE ?
    372			OUTPUT_MORE : INPUT_MORE;
    373	dcmds = state->dma_cmds;
    374	total = 0;
    375
    376	scsi_for_each_sg(cmd, scl, nseg, i) {
    377		dma_addr = sg_dma_address(scl);
    378		dma_len = sg_dma_len(scl);
    379		if (dma_len > 0xffff)
    380			panic("mac53c94: scatterlist element >= 64k");
    381		total += dma_len;
    382		dcmds->req_count = cpu_to_le16(dma_len);
    383		dcmds->command = cpu_to_le16(dma_cmd);
    384		dcmds->phy_addr = cpu_to_le32(dma_addr);
    385		dcmds->xfer_status = 0;
    386		++dcmds;
    387	}
    388
    389	dma_cmd += OUTPUT_LAST - OUTPUT_MORE;
    390	dcmds[-1].command = cpu_to_le16(dma_cmd);
    391	dcmds->command = cpu_to_le16(DBDMA_STOP);
    392	mac53c94_priv(cmd)->this_residual = total;
    393}
    394
    395static struct scsi_host_template mac53c94_template = {
    396	.proc_name	= "53c94",
    397	.name		= "53C94",
    398	.queuecommand	= mac53c94_queue,
    399	.eh_host_reset_handler = mac53c94_host_reset,
    400	.can_queue	= 1,
    401	.this_id	= 7,
    402	.sg_tablesize	= SG_ALL,
    403	.max_segment_size = 65535,
    404	.cmd_size	= sizeof(struct mac53c94_cmd_priv),
    405};
    406
    407static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *match)
    408{
    409	struct device_node *node = macio_get_of_node(mdev);
    410	struct pci_dev *pdev = macio_get_pci_dev(mdev);
    411	struct fsc_state *state;
    412	struct Scsi_Host *host;
    413	void *dma_cmd_space;
    414	const unsigned char *clkprop;
    415	int proplen, rc = -ENODEV;
    416
    417	if (macio_resource_count(mdev) != 2 || macio_irq_count(mdev) != 2) {
    418		printk(KERN_ERR "mac53c94: expected 2 addrs and intrs"
    419		       " (got %d/%d)\n",
    420		       macio_resource_count(mdev), macio_irq_count(mdev));
    421		return -ENODEV;
    422	}
    423
    424	if (macio_request_resources(mdev, "mac53c94") != 0) {
    425       		printk(KERN_ERR "mac53c94: unable to request memory resources");
    426		return -EBUSY;
    427	}
    428
    429       	host = scsi_host_alloc(&mac53c94_template, sizeof(struct fsc_state));
    430	if (host == NULL) {
    431		printk(KERN_ERR "mac53c94: couldn't register host");
    432		rc = -ENOMEM;
    433		goto out_release;
    434	}
    435
    436	state = (struct fsc_state *) host->hostdata;
    437	macio_set_drvdata(mdev, state);
    438	state->host = host;
    439	state->pdev = pdev;
    440	state->mdev = mdev;
    441
    442	state->regs = (struct mac53c94_regs __iomem *)
    443		ioremap(macio_resource_start(mdev, 0), 0x1000);
    444	state->intr = macio_irq(mdev, 0);
    445	state->dma = (struct dbdma_regs __iomem *)
    446		ioremap(macio_resource_start(mdev, 1), 0x1000);
    447	state->dmaintr = macio_irq(mdev, 1);
    448	if (state->regs == NULL || state->dma == NULL) {
    449		printk(KERN_ERR "mac53c94: ioremap failed for %pOF\n", node);
    450		goto out_free;
    451	}
    452
    453	clkprop = of_get_property(node, "clock-frequency", &proplen);
    454       	if (clkprop == NULL || proplen != sizeof(int)) {
    455       		printk(KERN_ERR "%pOF: can't get clock frequency, "
    456       		       "assuming 25MHz\n", node);
    457       		state->clk_freq = 25000000;
    458       	} else
    459       		state->clk_freq = *(int *)clkprop;
    460
    461       	/* Space for dma command list: +1 for stop command,
    462       	 * +1 to allow for aligning.
    463	 * XXX FIXME: Use DMA consistent routines
    464	 */
    465       	dma_cmd_space = kmalloc_array(host->sg_tablesize + 2,
    466					     sizeof(struct dbdma_cmd),
    467					     GFP_KERNEL);
    468	if (!dma_cmd_space) {
    469		printk(KERN_ERR "mac53c94: couldn't allocate dma "
    470		       "command space for %pOF\n", node);
    471		rc = -ENOMEM;
    472		goto out_free;
    473	}
    474
    475	state->dma_cmds = (struct dbdma_cmd *)DBDMA_ALIGN(dma_cmd_space);
    476	memset(state->dma_cmds, 0, (host->sg_tablesize + 1)
    477	       * sizeof(struct dbdma_cmd));
    478	state->dma_cmd_space = dma_cmd_space;
    479
    480	mac53c94_init(state);
    481
    482	if (request_irq(state->intr, do_mac53c94_interrupt, 0, "53C94",state)) {
    483		printk(KERN_ERR "mac53C94: can't get irq %d for %pOF\n",
    484		       state->intr, node);
    485		goto out_free_dma;
    486	}
    487
    488	rc = scsi_add_host(host, &mdev->ofdev.dev);
    489	if (rc != 0)
    490		goto out_release_irq;
    491
    492	scsi_scan_host(host);
    493	return 0;
    494
    495 out_release_irq:
    496	free_irq(state->intr, state);
    497 out_free_dma:
    498	kfree(state->dma_cmd_space);
    499 out_free:
    500	if (state->dma != NULL)
    501		iounmap(state->dma);
    502	if (state->regs != NULL)
    503		iounmap(state->regs);
    504	scsi_host_put(host);
    505 out_release:
    506	macio_release_resources(mdev);
    507
    508	return rc;
    509}
    510
    511static int mac53c94_remove(struct macio_dev *mdev)
    512{
    513	struct fsc_state *fp = (struct fsc_state *)macio_get_drvdata(mdev);
    514	struct Scsi_Host *host = fp->host;
    515
    516	scsi_remove_host(host);
    517
    518	free_irq(fp->intr, fp);
    519
    520	if (fp->regs)
    521		iounmap(fp->regs);
    522	if (fp->dma)
    523		iounmap(fp->dma);
    524	kfree(fp->dma_cmd_space);
    525
    526	scsi_host_put(host);
    527
    528	macio_release_resources(mdev);
    529
    530	return 0;
    531}
    532
    533
    534static struct of_device_id mac53c94_match[] = 
    535{
    536	{
    537	.name 		= "53c94",
    538	},
    539	{},
    540};
    541MODULE_DEVICE_TABLE (of, mac53c94_match);
    542
    543static struct macio_driver mac53c94_driver = 
    544{
    545	.driver = {
    546		.name 		= "mac53c94",
    547		.owner		= THIS_MODULE,
    548		.of_match_table	= mac53c94_match,
    549	},
    550	.probe		= mac53c94_probe,
    551	.remove		= mac53c94_remove,
    552};
    553
    554
    555static int __init init_mac53c94(void)
    556{
    557	return macio_register_driver(&mac53c94_driver);
    558}
    559
    560static void __exit exit_mac53c94(void)
    561{
    562	return macio_unregister_driver(&mac53c94_driver);
    563}
    564
    565module_init(init_mac53c94);
    566module_exit(exit_mac53c94);
    567
    568MODULE_DESCRIPTION("PowerMac 53c94 SCSI driver");
    569MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>");
    570MODULE_LICENSE("GPL");