Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Generic Macintosh NCR5380 driver
0004  *
0005  * Copyright 1998, Michael Schmitz <mschmitz@lbl.gov>
0006  *
0007  * Copyright 2019 Finn Thain
0008  *
0009  * derived in part from:
0010  */
0011 /*
0012  * Generic Generic NCR5380 driver
0013  *
0014  * Copyright 1995, Russell King
0015  */
0016 
0017 #include <linux/delay.h>
0018 #include <linux/types.h>
0019 #include <linux/module.h>
0020 #include <linux/ioport.h>
0021 #include <linux/init.h>
0022 #include <linux/blkdev.h>
0023 #include <linux/interrupt.h>
0024 #include <linux/platform_device.h>
0025 
0026 #include <asm/hwtest.h>
0027 #include <asm/io.h>
0028 #include <asm/macintosh.h>
0029 #include <asm/macints.h>
0030 #include <asm/setup.h>
0031 
0032 #include <scsi/scsi_host.h>
0033 
0034 /* Definitions for the core NCR5380 driver. */
0035 
0036 #define NCR5380_implementation_fields   int pdma_residual
0037 
0038 #define NCR5380_read(reg)           in_8(hostdata->io + ((reg) << 4))
0039 #define NCR5380_write(reg, value)   out_8(hostdata->io + ((reg) << 4), value)
0040 
0041 #define NCR5380_dma_xfer_len            macscsi_dma_xfer_len
0042 #define NCR5380_dma_recv_setup          macscsi_pread
0043 #define NCR5380_dma_send_setup          macscsi_pwrite
0044 #define NCR5380_dma_residual            macscsi_dma_residual
0045 
0046 #define NCR5380_intr                    macscsi_intr
0047 #define NCR5380_queue_command           macscsi_queue_command
0048 #define NCR5380_abort                   macscsi_abort
0049 #define NCR5380_host_reset              macscsi_host_reset
0050 #define NCR5380_info                    macscsi_info
0051 
0052 #include "NCR5380.h"
0053 
0054 static int setup_can_queue = -1;
0055 module_param(setup_can_queue, int, 0);
0056 static int setup_cmd_per_lun = -1;
0057 module_param(setup_cmd_per_lun, int, 0);
0058 static int setup_sg_tablesize = -1;
0059 module_param(setup_sg_tablesize, int, 0);
0060 static int setup_use_pdma = 512;
0061 module_param(setup_use_pdma, int, 0);
0062 static int setup_hostid = -1;
0063 module_param(setup_hostid, int, 0);
0064 static int setup_toshiba_delay = -1;
0065 module_param(setup_toshiba_delay, int, 0);
0066 
0067 #ifndef MODULE
0068 static int __init mac_scsi_setup(char *str)
0069 {
0070     int ints[8];
0071 
0072     (void)get_options(str, ARRAY_SIZE(ints), ints);
0073 
0074     if (ints[0] < 1) {
0075         pr_err("Usage: mac5380=<can_queue>[,<cmd_per_lun>[,<sg_tablesize>[,<hostid>[,<use_tags>[,<use_pdma>[,<toshiba_delay>]]]]]]\n");
0076         return 0;
0077     }
0078     if (ints[0] >= 1)
0079         setup_can_queue = ints[1];
0080     if (ints[0] >= 2)
0081         setup_cmd_per_lun = ints[2];
0082     if (ints[0] >= 3)
0083         setup_sg_tablesize = ints[3];
0084     if (ints[0] >= 4)
0085         setup_hostid = ints[4];
0086     /* ints[5] (use_tagged_queuing) is ignored */
0087     if (ints[0] >= 6)
0088         setup_use_pdma = ints[6];
0089     if (ints[0] >= 7)
0090         setup_toshiba_delay = ints[7];
0091     return 1;
0092 }
0093 
0094 __setup("mac5380=", mac_scsi_setup);
0095 #endif /* !MODULE */
0096 
0097 /*
0098  * According to "Inside Macintosh: Devices", Mac OS requires disk drivers to
0099  * specify the number of bytes between the delays expected from a SCSI target.
0100  * This allows the operating system to "prevent bus errors when a target fails
0101  * to deliver the next byte within the processor bus error timeout period."
0102  * Linux SCSI drivers lack knowledge of the timing behaviour of SCSI targets
0103  * so bus errors are unavoidable.
0104  *
0105  * If a MOVE.B instruction faults, we assume that zero bytes were transferred
0106  * and simply retry. That assumption probably depends on target behaviour but
0107  * seems to hold up okay. The NOP provides synchronization: without it the
0108  * fault can sometimes occur after the program counter has moved past the
0109  * offending instruction. Post-increment addressing can't be used.
0110  */
0111 
0112 #define MOVE_BYTE(operands) \
0113     asm volatile ( \
0114         "1:     moveb " operands "     \n" \
0115         "11:    nop                    \n" \
0116         "       addq #1,%0             \n" \
0117         "       subq #1,%1             \n" \
0118         "40:                           \n" \
0119         "                              \n" \
0120         ".section .fixup,\"ax\"        \n" \
0121         ".even                         \n" \
0122         "90:    movel #1, %2           \n" \
0123         "       jra 40b                \n" \
0124         ".previous                     \n" \
0125         "                              \n" \
0126         ".section __ex_table,\"a\"     \n" \
0127         ".align  4                     \n" \
0128         ".long   1b,90b                \n" \
0129         ".long  11b,90b                \n" \
0130         ".previous                     \n" \
0131         : "+a" (addr), "+r" (n), "+r" (result) : "a" (io))
0132 
0133 /*
0134  * If a MOVE.W (or MOVE.L) instruction faults, it cannot be retried because
0135  * the residual byte count would be uncertain. In that situation the MOVE_WORD
0136  * macro clears n in the fixup section to abort the transfer.
0137  */
0138 
0139 #define MOVE_WORD(operands) \
0140     asm volatile ( \
0141         "1:     movew " operands "     \n" \
0142         "11:    nop                    \n" \
0143         "       subq #2,%1             \n" \
0144         "40:                           \n" \
0145         "                              \n" \
0146         ".section .fixup,\"ax\"        \n" \
0147         ".even                         \n" \
0148         "90:    movel #0, %1           \n" \
0149         "       movel #2, %2           \n" \
0150         "       jra 40b                \n" \
0151         ".previous                     \n" \
0152         "                              \n" \
0153         ".section __ex_table,\"a\"     \n" \
0154         ".align  4                     \n" \
0155         ".long   1b,90b                \n" \
0156         ".long  11b,90b                \n" \
0157         ".previous                     \n" \
0158         : "+a" (addr), "+r" (n), "+r" (result) : "a" (io))
0159 
0160 #define MOVE_16_WORDS(operands) \
0161     asm volatile ( \
0162         "1:     movew " operands "     \n" \
0163         "2:     movew " operands "     \n" \
0164         "3:     movew " operands "     \n" \
0165         "4:     movew " operands "     \n" \
0166         "5:     movew " operands "     \n" \
0167         "6:     movew " operands "     \n" \
0168         "7:     movew " operands "     \n" \
0169         "8:     movew " operands "     \n" \
0170         "9:     movew " operands "     \n" \
0171         "10:    movew " operands "     \n" \
0172         "11:    movew " operands "     \n" \
0173         "12:    movew " operands "     \n" \
0174         "13:    movew " operands "     \n" \
0175         "14:    movew " operands "     \n" \
0176         "15:    movew " operands "     \n" \
0177         "16:    movew " operands "     \n" \
0178         "17:    nop                    \n" \
0179         "       subl  #32,%1           \n" \
0180         "40:                           \n" \
0181         "                              \n" \
0182         ".section .fixup,\"ax\"        \n" \
0183         ".even                         \n" \
0184         "90:    movel #0, %1           \n" \
0185         "       movel #2, %2           \n" \
0186         "       jra 40b                \n" \
0187         ".previous                     \n" \
0188         "                              \n" \
0189         ".section __ex_table,\"a\"     \n" \
0190         ".align  4                     \n" \
0191         ".long   1b,90b                \n" \
0192         ".long   2b,90b                \n" \
0193         ".long   3b,90b                \n" \
0194         ".long   4b,90b                \n" \
0195         ".long   5b,90b                \n" \
0196         ".long   6b,90b                \n" \
0197         ".long   7b,90b                \n" \
0198         ".long   8b,90b                \n" \
0199         ".long   9b,90b                \n" \
0200         ".long  10b,90b                \n" \
0201         ".long  11b,90b                \n" \
0202         ".long  12b,90b                \n" \
0203         ".long  13b,90b                \n" \
0204         ".long  14b,90b                \n" \
0205         ".long  15b,90b                \n" \
0206         ".long  16b,90b                \n" \
0207         ".long  17b,90b                \n" \
0208         ".previous                     \n" \
0209         : "+a" (addr), "+r" (n), "+r" (result) : "a" (io))
0210 
0211 #define MAC_PDMA_DELAY      32
0212 
0213 static inline int mac_pdma_recv(void __iomem *io, unsigned char *start, int n)
0214 {
0215     unsigned char *addr = start;
0216     int result = 0;
0217 
0218     if (n >= 1) {
0219         MOVE_BYTE("%3@,%0@");
0220         if (result)
0221             goto out;
0222     }
0223     if (n >= 1 && ((unsigned long)addr & 1)) {
0224         MOVE_BYTE("%3@,%0@");
0225         if (result)
0226             goto out;
0227     }
0228     while (n >= 32)
0229         MOVE_16_WORDS("%3@,%0@+");
0230     while (n >= 2)
0231         MOVE_WORD("%3@,%0@+");
0232     if (result)
0233         return start - addr; /* Negated to indicate uncertain length */
0234     if (n == 1)
0235         MOVE_BYTE("%3@,%0@");
0236 out:
0237     return addr - start;
0238 }
0239 
0240 static inline int mac_pdma_send(unsigned char *start, void __iomem *io, int n)
0241 {
0242     unsigned char *addr = start;
0243     int result = 0;
0244 
0245     if (n >= 1) {
0246         MOVE_BYTE("%0@,%3@");
0247         if (result)
0248             goto out;
0249     }
0250     if (n >= 1 && ((unsigned long)addr & 1)) {
0251         MOVE_BYTE("%0@,%3@");
0252         if (result)
0253             goto out;
0254     }
0255     while (n >= 32)
0256         MOVE_16_WORDS("%0@+,%3@");
0257     while (n >= 2)
0258         MOVE_WORD("%0@+,%3@");
0259     if (result)
0260         return start - addr; /* Negated to indicate uncertain length */
0261     if (n == 1)
0262         MOVE_BYTE("%0@,%3@");
0263 out:
0264     return addr - start;
0265 }
0266 
0267 /* The "SCSI DMA" chip on the IIfx implements this register. */
0268 #define CTRL_REG                0x8
0269 #define CTRL_INTERRUPTS_ENABLE  BIT(1)
0270 #define CTRL_HANDSHAKE_MODE     BIT(3)
0271 
0272 static inline void write_ctrl_reg(struct NCR5380_hostdata *hostdata, u32 value)
0273 {
0274     out_be32(hostdata->io + (CTRL_REG << 4), value);
0275 }
0276 
0277 static inline int macscsi_pread(struct NCR5380_hostdata *hostdata,
0278                                 unsigned char *dst, int len)
0279 {
0280     u8 __iomem *s = hostdata->pdma_io + (INPUT_DATA_REG << 4);
0281     unsigned char *d = dst;
0282     int result = 0;
0283 
0284     hostdata->pdma_residual = len;
0285 
0286     while (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG,
0287                                   BASR_DRQ | BASR_PHASE_MATCH,
0288                                   BASR_DRQ | BASR_PHASE_MATCH, 0)) {
0289         int bytes;
0290 
0291         if (macintosh_config->ident == MAC_MODEL_IIFX)
0292             write_ctrl_reg(hostdata, CTRL_HANDSHAKE_MODE |
0293                                      CTRL_INTERRUPTS_ENABLE);
0294 
0295         bytes = mac_pdma_recv(s, d, min(hostdata->pdma_residual, 512));
0296 
0297         if (bytes > 0) {
0298             d += bytes;
0299             hostdata->pdma_residual -= bytes;
0300         }
0301 
0302         if (hostdata->pdma_residual == 0)
0303             goto out;
0304 
0305         if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ,
0306                                    BUS_AND_STATUS_REG, BASR_ACK,
0307                                    BASR_ACK, 0) < 0)
0308             scmd_printk(KERN_DEBUG, hostdata->connected,
0309                         "%s: !REQ and !ACK\n", __func__);
0310         if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH))
0311             goto out;
0312 
0313         if (bytes == 0)
0314             udelay(MAC_PDMA_DELAY);
0315 
0316         if (bytes >= 0)
0317             continue;
0318 
0319         dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host,
0320                  "%s: bus error (%d/%d)\n", __func__, d - dst, len);
0321         NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
0322         result = -1;
0323         goto out;
0324     }
0325 
0326     scmd_printk(KERN_ERR, hostdata->connected,
0327                 "%s: phase mismatch or !DRQ\n", __func__);
0328     NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
0329     result = -1;
0330 out:
0331     if (macintosh_config->ident == MAC_MODEL_IIFX)
0332         write_ctrl_reg(hostdata, CTRL_INTERRUPTS_ENABLE);
0333     return result;
0334 }
0335 
0336 static inline int macscsi_pwrite(struct NCR5380_hostdata *hostdata,
0337                                  unsigned char *src, int len)
0338 {
0339     unsigned char *s = src;
0340     u8 __iomem *d = hostdata->pdma_io + (OUTPUT_DATA_REG << 4);
0341     int result = 0;
0342 
0343     hostdata->pdma_residual = len;
0344 
0345     while (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG,
0346                                   BASR_DRQ | BASR_PHASE_MATCH,
0347                                   BASR_DRQ | BASR_PHASE_MATCH, 0)) {
0348         int bytes;
0349 
0350         if (macintosh_config->ident == MAC_MODEL_IIFX)
0351             write_ctrl_reg(hostdata, CTRL_HANDSHAKE_MODE |
0352                                      CTRL_INTERRUPTS_ENABLE);
0353 
0354         bytes = mac_pdma_send(s, d, min(hostdata->pdma_residual, 512));
0355 
0356         if (bytes > 0) {
0357             s += bytes;
0358             hostdata->pdma_residual -= bytes;
0359         }
0360 
0361         if (hostdata->pdma_residual == 0) {
0362             if (NCR5380_poll_politely(hostdata, TARGET_COMMAND_REG,
0363                                       TCR_LAST_BYTE_SENT,
0364                                       TCR_LAST_BYTE_SENT,
0365                                       0) < 0) {
0366                 scmd_printk(KERN_ERR, hostdata->connected,
0367                             "%s: Last Byte Sent timeout\n", __func__);
0368                 result = -1;
0369             }
0370             goto out;
0371         }
0372 
0373         if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ,
0374                                    BUS_AND_STATUS_REG, BASR_ACK,
0375                                    BASR_ACK, 0) < 0)
0376             scmd_printk(KERN_DEBUG, hostdata->connected,
0377                         "%s: !REQ and !ACK\n", __func__);
0378         if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH))
0379             goto out;
0380 
0381         if (bytes == 0)
0382             udelay(MAC_PDMA_DELAY);
0383 
0384         if (bytes >= 0)
0385             continue;
0386 
0387         dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host,
0388                  "%s: bus error (%d/%d)\n", __func__, s - src, len);
0389         NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
0390         result = -1;
0391         goto out;
0392     }
0393 
0394     scmd_printk(KERN_ERR, hostdata->connected,
0395                 "%s: phase mismatch or !DRQ\n", __func__);
0396     NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
0397     result = -1;
0398 out:
0399     if (macintosh_config->ident == MAC_MODEL_IIFX)
0400         write_ctrl_reg(hostdata, CTRL_INTERRUPTS_ENABLE);
0401     return result;
0402 }
0403 
0404 static int macscsi_dma_xfer_len(struct NCR5380_hostdata *hostdata,
0405                                 struct scsi_cmnd *cmd)
0406 {
0407     int resid = NCR5380_to_ncmd(cmd)->this_residual;
0408 
0409     if (hostdata->flags & FLAG_NO_PSEUDO_DMA || resid < setup_use_pdma)
0410         return 0;
0411 
0412     return resid;
0413 }
0414 
0415 static int macscsi_dma_residual(struct NCR5380_hostdata *hostdata)
0416 {
0417     return hostdata->pdma_residual;
0418 }
0419 
0420 #include "NCR5380.c"
0421 
0422 #define DRV_MODULE_NAME         "mac_scsi"
0423 #define PFX                     DRV_MODULE_NAME ": "
0424 
0425 static struct scsi_host_template mac_scsi_template = {
0426     .module         = THIS_MODULE,
0427     .proc_name      = DRV_MODULE_NAME,
0428     .name           = "Macintosh NCR5380 SCSI",
0429     .info           = macscsi_info,
0430     .queuecommand       = macscsi_queue_command,
0431     .eh_abort_handler   = macscsi_abort,
0432     .eh_host_reset_handler  = macscsi_host_reset,
0433     .can_queue      = 16,
0434     .this_id        = 7,
0435     .sg_tablesize       = 1,
0436     .cmd_per_lun        = 2,
0437     .dma_boundary       = PAGE_SIZE - 1,
0438     .cmd_size       = sizeof(struct NCR5380_cmd),
0439     .max_sectors        = 128,
0440 };
0441 
0442 static int __init mac_scsi_probe(struct platform_device *pdev)
0443 {
0444     struct Scsi_Host *instance;
0445     struct NCR5380_hostdata *hostdata;
0446     int error;
0447     int host_flags = 0;
0448     struct resource *irq, *pio_mem, *pdma_mem = NULL;
0449 
0450     pio_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0451     if (!pio_mem)
0452         return -ENODEV;
0453 
0454     pdma_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
0455 
0456     irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
0457 
0458     if (!hwreg_present((unsigned char *)pio_mem->start +
0459                        (STATUS_REG << 4))) {
0460         pr_info(PFX "no device detected at %pap\n", &pio_mem->start);
0461         return -ENODEV;
0462     }
0463 
0464     if (setup_can_queue > 0)
0465         mac_scsi_template.can_queue = setup_can_queue;
0466     if (setup_cmd_per_lun > 0)
0467         mac_scsi_template.cmd_per_lun = setup_cmd_per_lun;
0468     if (setup_sg_tablesize > 0)
0469         mac_scsi_template.sg_tablesize = setup_sg_tablesize;
0470     if (setup_hostid >= 0)
0471         mac_scsi_template.this_id = setup_hostid & 7;
0472 
0473     instance = scsi_host_alloc(&mac_scsi_template,
0474                                sizeof(struct NCR5380_hostdata));
0475     if (!instance)
0476         return -ENOMEM;
0477 
0478     if (irq)
0479         instance->irq = irq->start;
0480     else
0481         instance->irq = NO_IRQ;
0482 
0483     hostdata = shost_priv(instance);
0484     hostdata->base = pio_mem->start;
0485     hostdata->io = (u8 __iomem *)pio_mem->start;
0486 
0487     if (pdma_mem && setup_use_pdma)
0488         hostdata->pdma_io = (u8 __iomem *)pdma_mem->start;
0489     else
0490         host_flags |= FLAG_NO_PSEUDO_DMA;
0491 
0492     host_flags |= setup_toshiba_delay > 0 ? FLAG_TOSHIBA_DELAY : 0;
0493 
0494     error = NCR5380_init(instance, host_flags | FLAG_LATE_DMA_SETUP);
0495     if (error)
0496         goto fail_init;
0497 
0498     if (instance->irq != NO_IRQ) {
0499         error = request_irq(instance->irq, macscsi_intr, IRQF_SHARED,
0500                             "NCR5380", instance);
0501         if (error)
0502             goto fail_irq;
0503     }
0504 
0505     NCR5380_maybe_reset_bus(instance);
0506 
0507     error = scsi_add_host(instance, NULL);
0508     if (error)
0509         goto fail_host;
0510 
0511     platform_set_drvdata(pdev, instance);
0512 
0513     scsi_scan_host(instance);
0514     return 0;
0515 
0516 fail_host:
0517     if (instance->irq != NO_IRQ)
0518         free_irq(instance->irq, instance);
0519 fail_irq:
0520     NCR5380_exit(instance);
0521 fail_init:
0522     scsi_host_put(instance);
0523     return error;
0524 }
0525 
0526 static int __exit mac_scsi_remove(struct platform_device *pdev)
0527 {
0528     struct Scsi_Host *instance = platform_get_drvdata(pdev);
0529 
0530     scsi_remove_host(instance);
0531     if (instance->irq != NO_IRQ)
0532         free_irq(instance->irq, instance);
0533     NCR5380_exit(instance);
0534     scsi_host_put(instance);
0535     return 0;
0536 }
0537 
0538 static struct platform_driver mac_scsi_driver = {
0539     .remove = __exit_p(mac_scsi_remove),
0540     .driver = {
0541         .name   = DRV_MODULE_NAME,
0542     },
0543 };
0544 
0545 module_platform_driver_probe(mac_scsi_driver, mac_scsi_probe);
0546 
0547 MODULE_ALIAS("platform:" DRV_MODULE_NAME);
0548 MODULE_LICENSE("GPL");