1 /* 2 * Oak Generic NCR5380 driver 3 * 4 * Copyright 1995-2002, Russell King 5 */ 6 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 19 #define NCR5380_read(reg) \ 20 readb(priv(instance)->base + ((reg) << 2)) 21 #define NCR5380_write(reg, value) \ 22 writeb(value, priv(instance)->base + ((reg) << 2)) 23 24 #define NCR5380_dma_xfer_len(instance, cmd, phase) (0) 25 #define NCR5380_dma_recv_setup oakscsi_pread 26 #define NCR5380_dma_send_setup oakscsi_pwrite 27 #define NCR5380_dma_residual(instance) (0) 28 29 #define NCR5380_queue_command oakscsi_queue_command 30 #define NCR5380_info oakscsi_info 31 32 #define NCR5380_implementation_fields \ 33 void __iomem *base 34 35 #include "../NCR5380.h" 36 37 #undef START_DMA_INITIATOR_RECEIVE_REG 38 #define START_DMA_INITIATOR_RECEIVE_REG (128 + 7) 39 40 #define STAT ((128 + 16) << 2) 41 #define DATA ((128 + 8) << 2) 42 43 static inline int oakscsi_pwrite(struct Scsi_Host *instance, 44 unsigned char *addr, int len) 45 { 46 void __iomem *base = priv(instance)->base; 47 48 printk("writing %p len %d\n",addr, len); 49 50 while(1) 51 { 52 int status; 53 while (((status = readw(base + STAT)) & 0x100)==0); 54 } 55 return 0; 56 } 57 58 static inline int oakscsi_pread(struct Scsi_Host *instance, 59 unsigned char *addr, int len) 60 { 61 void __iomem *base = priv(instance)->base; 62 printk("reading %p len %d\n", addr, len); 63 while(len > 0) 64 { 65 unsigned int status, timeout; 66 unsigned long b; 67 68 timeout = 0x01FFFFFF; 69 70 while (((status = readw(base + STAT)) & 0x100)==0) 71 { 72 timeout--; 73 if(status & 0x200 || !timeout) 74 { 75 printk("status = %08X\n", status); 76 return -1; 77 } 78 } 79 80 if(len >= 128) 81 { 82 readsw(base + DATA, addr, 128); 83 addr += 128; 84 len -= 128; 85 } 86 else 87 { 88 b = (unsigned long) readw(base + DATA); 89 *addr ++ = b; 90 len -= 1; 91 if(len) 92 *addr ++ = b>>8; 93 len -= 1; 94 } 95 } 96 return 0; 97 } 98 99 #undef STAT 100 #undef DATA 101 102 #include "../NCR5380.c" 103 104 static struct scsi_host_template oakscsi_template = { 105 .module = THIS_MODULE, 106 .name = "Oak 16-bit SCSI", 107 .info = oakscsi_info, 108 .queuecommand = oakscsi_queue_command, 109 .eh_abort_handler = NCR5380_abort, 110 .eh_bus_reset_handler = NCR5380_bus_reset, 111 .can_queue = 16, 112 .this_id = 7, 113 .sg_tablesize = SG_ALL, 114 .cmd_per_lun = 2, 115 .use_clustering = DISABLE_CLUSTERING, 116 .proc_name = "oakscsi", 117 .cmd_size = NCR5380_CMD_SIZE, 118 .max_sectors = 128, 119 }; 120 121 static int oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id) 122 { 123 struct Scsi_Host *host; 124 int ret = -ENOMEM; 125 126 ret = ecard_request_resources(ec); 127 if (ret) 128 goto out; 129 130 host = scsi_host_alloc(&oakscsi_template, sizeof(struct NCR5380_hostdata)); 131 if (!host) { 132 ret = -ENOMEM; 133 goto release; 134 } 135 136 priv(host)->base = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC), 137 ecard_resource_len(ec, ECARD_RES_MEMC)); 138 if (!priv(host)->base) { 139 ret = -ENOMEM; 140 goto unreg; 141 } 142 143 host->irq = NO_IRQ; 144 host->n_io_port = 255; 145 146 ret = NCR5380_init(host, FLAG_DMA_FIXUP | FLAG_LATE_DMA_SETUP); 147 if (ret) 148 goto out_unmap; 149 150 NCR5380_maybe_reset_bus(host); 151 152 ret = scsi_add_host(host, &ec->dev); 153 if (ret) 154 goto out_exit; 155 156 scsi_scan_host(host); 157 goto out; 158 159 out_exit: 160 NCR5380_exit(host); 161 out_unmap: 162 iounmap(priv(host)->base); 163 unreg: 164 scsi_host_put(host); 165 release: 166 ecard_release_resources(ec); 167 out: 168 return ret; 169 } 170 171 static void oakscsi_remove(struct expansion_card *ec) 172 { 173 struct Scsi_Host *host = ecard_get_drvdata(ec); 174 175 ecard_set_drvdata(ec, NULL); 176 scsi_remove_host(host); 177 178 NCR5380_exit(host); 179 iounmap(priv(host)->base); 180 scsi_host_put(host); 181 ecard_release_resources(ec); 182 } 183 184 static const struct ecard_id oakscsi_cids[] = { 185 { MANU_OAK, PROD_OAK_SCSI }, 186 { 0xffff, 0xffff } 187 }; 188 189 static struct ecard_driver oakscsi_driver = { 190 .probe = oakscsi_probe, 191 .remove = oakscsi_remove, 192 .id_table = oakscsi_cids, 193 .drv = { 194 .name = "oakscsi", 195 }, 196 }; 197 198 static int __init oakscsi_init(void) 199 { 200 return ecard_register_driver(&oakscsi_driver); 201 } 202 203 static void __exit oakscsi_exit(void) 204 { 205 ecard_remove_driver(&oakscsi_driver); 206 } 207 208 module_init(oakscsi_init); 209 module_exit(oakscsi_exit); 210 211 MODULE_AUTHOR("Russell King"); 212 MODULE_DESCRIPTION("Oak SCSI driver"); 213 MODULE_LICENSE("GPL"); 214 215