0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082 #include <linux/module.h>
0083 #include <linux/interrupt.h>
0084 #include <linux/delay.h>
0085 #include <linux/pci.h>
0086 #include <linux/workqueue.h>
0087 #include <scsi/scsicam.h>
0088 #include <scsi/scsi_cmnd.h>
0089 #include <scsi/scsi_device.h>
0090 #include <scsi/scsi_host.h>
0091 #include "fdomain.h"
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101 #define FIFO_COUNT 2
0102 #define PARITY_MASK ACTL_PAREN
0103
0104 enum chip_type {
0105 unknown = 0x00,
0106 tmc1800 = 0x01,
0107 tmc18c50 = 0x02,
0108 tmc18c30 = 0x03,
0109 };
0110
0111 struct fdomain {
0112 int base;
0113 struct scsi_cmnd *cur_cmd;
0114 enum chip_type chip;
0115 struct work_struct work;
0116 };
0117
0118 static struct scsi_pointer *fdomain_scsi_pointer(struct scsi_cmnd *cmd)
0119 {
0120 return scsi_cmd_priv(cmd);
0121 }
0122
0123 static inline void fdomain_make_bus_idle(struct fdomain *fd)
0124 {
0125 outb(0, fd->base + REG_BCTL);
0126 outb(0, fd->base + REG_MCTL);
0127 if (fd->chip == tmc18c50 || fd->chip == tmc18c30)
0128
0129 outb(ACTL_RESET | ACTL_CLRFIRQ | PARITY_MASK,
0130 fd->base + REG_ACTL);
0131 else
0132 outb(ACTL_RESET | PARITY_MASK, fd->base + REG_ACTL);
0133 }
0134
0135 static enum chip_type fdomain_identify(int port)
0136 {
0137 u16 id = inb(port + REG_ID_LSB) | inb(port + REG_ID_MSB) << 8;
0138
0139 switch (id) {
0140 case 0x6127:
0141 return tmc1800;
0142 case 0x60e9:
0143 break;
0144 default:
0145 return unknown;
0146 }
0147
0148
0149 outb(CFG2_32BIT, port + REG_CFG2);
0150 if ((inb(port + REG_CFG2) & CFG2_32BIT)) {
0151 outb(0, port + REG_CFG2);
0152 if ((inb(port + REG_CFG2) & CFG2_32BIT) == 0)
0153 return tmc18c30;
0154 }
0155
0156 return tmc18c50;
0157 }
0158
0159 static int fdomain_test_loopback(int base)
0160 {
0161 int i;
0162
0163 for (i = 0; i < 255; i++) {
0164 outb(i, base + REG_LOOPBACK);
0165 if (inb(base + REG_LOOPBACK) != i)
0166 return 1;
0167 }
0168
0169 return 0;
0170 }
0171
0172 static void fdomain_reset(int base)
0173 {
0174 outb(BCTL_RST, base + REG_BCTL);
0175 mdelay(20);
0176 outb(0, base + REG_BCTL);
0177 mdelay(1150);
0178 outb(0, base + REG_MCTL);
0179 outb(PARITY_MASK, base + REG_ACTL);
0180 }
0181
0182 static int fdomain_select(struct Scsi_Host *sh, int target)
0183 {
0184 int status;
0185 unsigned long timeout;
0186 struct fdomain *fd = shost_priv(sh);
0187
0188 outb(BCTL_BUSEN | BCTL_SEL, fd->base + REG_BCTL);
0189 outb(BIT(sh->this_id) | BIT(target), fd->base + REG_SCSI_DATA_NOACK);
0190
0191
0192 outb(PARITY_MASK, fd->base + REG_ACTL);
0193
0194 timeout = 350;
0195
0196 do {
0197 status = inb(fd->base + REG_BSTAT);
0198 if (status & BSTAT_BSY) {
0199
0200
0201 outb(BCTL_BUSEN, fd->base + REG_BCTL);
0202 return 0;
0203 }
0204 mdelay(1);
0205 } while (--timeout);
0206 fdomain_make_bus_idle(fd);
0207 return 1;
0208 }
0209
0210 static void fdomain_finish_cmd(struct fdomain *fd)
0211 {
0212 outb(0, fd->base + REG_ICTL);
0213 fdomain_make_bus_idle(fd);
0214 scsi_done(fd->cur_cmd);
0215 fd->cur_cmd = NULL;
0216 }
0217
0218 static void fdomain_read_data(struct scsi_cmnd *cmd)
0219 {
0220 struct fdomain *fd = shost_priv(cmd->device->host);
0221 unsigned char *virt, *ptr;
0222 size_t offset, len;
0223
0224 while ((len = inw(fd->base + REG_FIFO_COUNT)) > 0) {
0225 offset = scsi_bufflen(cmd) - scsi_get_resid(cmd);
0226 virt = scsi_kmap_atomic_sg(scsi_sglist(cmd), scsi_sg_count(cmd),
0227 &offset, &len);
0228 ptr = virt + offset;
0229 if (len & 1)
0230 *ptr++ = inb(fd->base + REG_FIFO);
0231 if (len > 1)
0232 insw(fd->base + REG_FIFO, ptr, len >> 1);
0233 scsi_set_resid(cmd, scsi_get_resid(cmd) - len);
0234 scsi_kunmap_atomic_sg(virt);
0235 }
0236 }
0237
0238 static void fdomain_write_data(struct scsi_cmnd *cmd)
0239 {
0240 struct fdomain *fd = shost_priv(cmd->device->host);
0241
0242 int FIFO_Size = fd->chip == tmc18c30 ? 0x800 : 0x2000;
0243 unsigned char *virt, *ptr;
0244 size_t offset, len;
0245
0246 while ((len = FIFO_Size - inw(fd->base + REG_FIFO_COUNT)) > 512) {
0247 offset = scsi_bufflen(cmd) - scsi_get_resid(cmd);
0248 if (len + offset > scsi_bufflen(cmd)) {
0249 len = scsi_bufflen(cmd) - offset;
0250 if (len == 0)
0251 break;
0252 }
0253 virt = scsi_kmap_atomic_sg(scsi_sglist(cmd), scsi_sg_count(cmd),
0254 &offset, &len);
0255 ptr = virt + offset;
0256 if (len & 1)
0257 outb(*ptr++, fd->base + REG_FIFO);
0258 if (len > 1)
0259 outsw(fd->base + REG_FIFO, ptr, len >> 1);
0260 scsi_set_resid(cmd, scsi_get_resid(cmd) - len);
0261 scsi_kunmap_atomic_sg(virt);
0262 }
0263 }
0264
0265 static void fdomain_work(struct work_struct *work)
0266 {
0267 struct fdomain *fd = container_of(work, struct fdomain, work);
0268 struct Scsi_Host *sh = container_of((void *)fd, struct Scsi_Host,
0269 hostdata);
0270 struct scsi_cmnd *cmd = fd->cur_cmd;
0271 struct scsi_pointer *scsi_pointer = fdomain_scsi_pointer(cmd);
0272 unsigned long flags;
0273 int status;
0274 int done = 0;
0275
0276 spin_lock_irqsave(sh->host_lock, flags);
0277
0278 if (scsi_pointer->phase & in_arbitration) {
0279 status = inb(fd->base + REG_ASTAT);
0280 if (!(status & ASTAT_ARB)) {
0281 set_host_byte(cmd, DID_BUS_BUSY);
0282 fdomain_finish_cmd(fd);
0283 goto out;
0284 }
0285 scsi_pointer->phase = in_selection;
0286
0287 outb(ICTL_SEL | FIFO_COUNT, fd->base + REG_ICTL);
0288 outb(BCTL_BUSEN | BCTL_SEL, fd->base + REG_BCTL);
0289 outb(BIT(cmd->device->host->this_id) | BIT(scmd_id(cmd)),
0290 fd->base + REG_SCSI_DATA_NOACK);
0291
0292 outb(ACTL_IRQEN | PARITY_MASK, fd->base + REG_ACTL);
0293 goto out;
0294 } else if (scsi_pointer->phase & in_selection) {
0295 status = inb(fd->base + REG_BSTAT);
0296 if (!(status & BSTAT_BSY)) {
0297
0298 if (fdomain_select(cmd->device->host, scmd_id(cmd))) {
0299 set_host_byte(cmd, DID_NO_CONNECT);
0300 fdomain_finish_cmd(fd);
0301 goto out;
0302 }
0303
0304 outb(ACTL_IRQEN | PARITY_MASK, fd->base + REG_ACTL);
0305 }
0306 scsi_pointer->phase = in_other;
0307 outb(ICTL_FIFO | ICTL_REQ | FIFO_COUNT, fd->base + REG_ICTL);
0308 outb(BCTL_BUSEN, fd->base + REG_BCTL);
0309 goto out;
0310 }
0311
0312
0313 status = inb(fd->base + REG_BSTAT);
0314
0315 if (status & BSTAT_REQ) {
0316 switch (status & (BSTAT_MSG | BSTAT_CMD | BSTAT_IO)) {
0317 case BSTAT_CMD:
0318 outb(cmd->cmnd[scsi_pointer->sent_command++],
0319 fd->base + REG_SCSI_DATA);
0320 break;
0321 case 0:
0322 if (fd->chip != tmc1800 && !scsi_pointer->have_data_in) {
0323 scsi_pointer->have_data_in = -1;
0324 outb(ACTL_IRQEN | ACTL_FIFOWR | ACTL_FIFOEN |
0325 PARITY_MASK, fd->base + REG_ACTL);
0326 }
0327 break;
0328 case BSTAT_IO:
0329 if (fd->chip != tmc1800 && !scsi_pointer->have_data_in) {
0330 scsi_pointer->have_data_in = 1;
0331 outb(ACTL_IRQEN | ACTL_FIFOEN | PARITY_MASK,
0332 fd->base + REG_ACTL);
0333 }
0334 break;
0335 case BSTAT_CMD | BSTAT_IO:
0336 scsi_pointer->Status = inb(fd->base + REG_SCSI_DATA);
0337 break;
0338 case BSTAT_MSG | BSTAT_CMD:
0339 outb(MESSAGE_REJECT, fd->base + REG_SCSI_DATA);
0340 break;
0341 case BSTAT_MSG | BSTAT_CMD | BSTAT_IO:
0342 scsi_pointer->Message = inb(fd->base + REG_SCSI_DATA);
0343 if (scsi_pointer->Message == COMMAND_COMPLETE)
0344 ++done;
0345 break;
0346 }
0347 }
0348
0349 if (fd->chip == tmc1800 && !scsi_pointer->have_data_in &&
0350 scsi_pointer->sent_command >= cmd->cmd_len) {
0351 if (cmd->sc_data_direction == DMA_TO_DEVICE) {
0352 scsi_pointer->have_data_in = -1;
0353 outb(ACTL_IRQEN | ACTL_FIFOWR | ACTL_FIFOEN |
0354 PARITY_MASK, fd->base + REG_ACTL);
0355 } else {
0356 scsi_pointer->have_data_in = 1;
0357 outb(ACTL_IRQEN | ACTL_FIFOEN | PARITY_MASK,
0358 fd->base + REG_ACTL);
0359 }
0360 }
0361
0362 if (scsi_pointer->have_data_in == -1)
0363 fdomain_write_data(cmd);
0364
0365 if (scsi_pointer->have_data_in == 1)
0366 fdomain_read_data(cmd);
0367
0368 if (done) {
0369 set_status_byte(cmd, scsi_pointer->Status);
0370 set_host_byte(cmd, DID_OK);
0371 scsi_msg_to_host_byte(cmd, scsi_pointer->Message);
0372 fdomain_finish_cmd(fd);
0373 } else {
0374 if (scsi_pointer->phase & disconnect) {
0375 outb(ICTL_FIFO | ICTL_SEL | ICTL_REQ | FIFO_COUNT,
0376 fd->base + REG_ICTL);
0377 outb(0, fd->base + REG_BCTL);
0378 } else
0379 outb(ICTL_FIFO | ICTL_REQ | FIFO_COUNT,
0380 fd->base + REG_ICTL);
0381 }
0382 out:
0383 spin_unlock_irqrestore(sh->host_lock, flags);
0384 }
0385
0386 static irqreturn_t fdomain_irq(int irq, void *dev_id)
0387 {
0388 struct fdomain *fd = dev_id;
0389
0390
0391 if ((inb(fd->base + REG_ASTAT) & ASTAT_IRQ) == 0)
0392 return IRQ_NONE;
0393
0394 outb(0, fd->base + REG_ICTL);
0395
0396
0397 if (!fd->cur_cmd)
0398 return IRQ_NONE;
0399
0400 schedule_work(&fd->work);
0401
0402 return IRQ_HANDLED;
0403 }
0404
0405 static int fdomain_queue(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
0406 {
0407 struct scsi_pointer *scsi_pointer = fdomain_scsi_pointer(cmd);
0408 struct fdomain *fd = shost_priv(cmd->device->host);
0409 unsigned long flags;
0410
0411 scsi_pointer->Status = 0;
0412 scsi_pointer->Message = 0;
0413 scsi_pointer->have_data_in = 0;
0414 scsi_pointer->sent_command = 0;
0415 scsi_pointer->phase = in_arbitration;
0416 scsi_set_resid(cmd, scsi_bufflen(cmd));
0417
0418 spin_lock_irqsave(sh->host_lock, flags);
0419
0420 fd->cur_cmd = cmd;
0421
0422 fdomain_make_bus_idle(fd);
0423
0424
0425 outb(0, fd->base + REG_ICTL);
0426 outb(0, fd->base + REG_BCTL);
0427
0428 outb(BIT(cmd->device->host->this_id), fd->base + REG_SCSI_DATA_NOACK);
0429 outb(ICTL_ARB, fd->base + REG_ICTL);
0430
0431 outb(ACTL_ARB | ACTL_IRQEN | PARITY_MASK, fd->base + REG_ACTL);
0432
0433 spin_unlock_irqrestore(sh->host_lock, flags);
0434
0435 return 0;
0436 }
0437
0438 static int fdomain_abort(struct scsi_cmnd *cmd)
0439 {
0440 struct Scsi_Host *sh = cmd->device->host;
0441 struct fdomain *fd = shost_priv(sh);
0442 unsigned long flags;
0443
0444 if (!fd->cur_cmd)
0445 return FAILED;
0446
0447 spin_lock_irqsave(sh->host_lock, flags);
0448
0449 fdomain_make_bus_idle(fd);
0450 fdomain_scsi_pointer(fd->cur_cmd)->phase |= aborted;
0451
0452
0453 set_host_byte(fd->cur_cmd, DID_ABORT);
0454 fdomain_finish_cmd(fd);
0455 spin_unlock_irqrestore(sh->host_lock, flags);
0456 return SUCCESS;
0457 }
0458
0459 static int fdomain_host_reset(struct scsi_cmnd *cmd)
0460 {
0461 struct Scsi_Host *sh = cmd->device->host;
0462 struct fdomain *fd = shost_priv(sh);
0463 unsigned long flags;
0464
0465 spin_lock_irqsave(sh->host_lock, flags);
0466 fdomain_reset(fd->base);
0467 spin_unlock_irqrestore(sh->host_lock, flags);
0468 return SUCCESS;
0469 }
0470
0471 static int fdomain_biosparam(struct scsi_device *sdev,
0472 struct block_device *bdev, sector_t capacity,
0473 int geom[])
0474 {
0475 unsigned char *p = scsi_bios_ptable(bdev);
0476
0477 if (p && p[65] == 0xaa && p[64] == 0x55
0478 && p[4]) {
0479 geom[0] = p[5] + 1;
0480 geom[1] = p[6] & 0x3f;
0481 } else {
0482 if (capacity >= 0x7e0000) {
0483 geom[0] = 255;
0484 geom[1] = 63;
0485 } else if (capacity >= 0x200000) {
0486 geom[0] = 128;
0487 geom[1] = 63;
0488 } else {
0489 geom[0] = 64;
0490 geom[1] = 32;
0491 }
0492 }
0493 geom[2] = sector_div(capacity, geom[0] * geom[1]);
0494 kfree(p);
0495
0496 return 0;
0497 }
0498
0499 static struct scsi_host_template fdomain_template = {
0500 .module = THIS_MODULE,
0501 .name = "Future Domain TMC-16x0",
0502 .proc_name = "fdomain",
0503 .queuecommand = fdomain_queue,
0504 .eh_abort_handler = fdomain_abort,
0505 .eh_host_reset_handler = fdomain_host_reset,
0506 .bios_param = fdomain_biosparam,
0507 .can_queue = 1,
0508 .this_id = 7,
0509 .sg_tablesize = 64,
0510 .dma_boundary = PAGE_SIZE - 1,
0511 .cmd_size = sizeof(struct scsi_pointer),
0512 };
0513
0514 struct Scsi_Host *fdomain_create(int base, int irq, int this_id,
0515 struct device *dev)
0516 {
0517 struct Scsi_Host *sh;
0518 struct fdomain *fd;
0519 enum chip_type chip;
0520 static const char * const chip_names[] = {
0521 "Unknown", "TMC-1800", "TMC-18C50", "TMC-18C30"
0522 };
0523 unsigned long irq_flags = 0;
0524
0525 chip = fdomain_identify(base);
0526 if (!chip)
0527 return NULL;
0528
0529 fdomain_reset(base);
0530
0531 if (fdomain_test_loopback(base))
0532 return NULL;
0533
0534 if (!irq) {
0535 dev_err(dev, "card has no IRQ assigned");
0536 return NULL;
0537 }
0538
0539 sh = scsi_host_alloc(&fdomain_template, sizeof(struct fdomain));
0540 if (!sh)
0541 return NULL;
0542
0543 if (this_id)
0544 sh->this_id = this_id & 0x07;
0545
0546 sh->irq = irq;
0547 sh->io_port = base;
0548 sh->n_io_port = FDOMAIN_REGION_SIZE;
0549
0550 fd = shost_priv(sh);
0551 fd->base = base;
0552 fd->chip = chip;
0553 INIT_WORK(&fd->work, fdomain_work);
0554
0555 if (dev_is_pci(dev) || !strcmp(dev->bus->name, "pcmcia"))
0556 irq_flags = IRQF_SHARED;
0557
0558 if (request_irq(irq, fdomain_irq, irq_flags, "fdomain", fd))
0559 goto fail_put;
0560
0561 shost_printk(KERN_INFO, sh, "%s chip at 0x%x irq %d SCSI ID %d\n",
0562 dev_is_pci(dev) ? "TMC-36C70 (PCI bus)" : chip_names[chip],
0563 base, irq, sh->this_id);
0564
0565 if (scsi_add_host(sh, dev))
0566 goto fail_free_irq;
0567
0568 scsi_scan_host(sh);
0569
0570 return sh;
0571
0572 fail_free_irq:
0573 free_irq(irq, fd);
0574 fail_put:
0575 scsi_host_put(sh);
0576 return NULL;
0577 }
0578 EXPORT_SYMBOL_GPL(fdomain_create);
0579
0580 int fdomain_destroy(struct Scsi_Host *sh)
0581 {
0582 struct fdomain *fd = shost_priv(sh);
0583
0584 cancel_work_sync(&fd->work);
0585 scsi_remove_host(sh);
0586 if (sh->irq)
0587 free_irq(sh->irq, fd);
0588 scsi_host_put(sh);
0589 return 0;
0590 }
0591 EXPORT_SYMBOL_GPL(fdomain_destroy);
0592
0593 #ifdef CONFIG_PM_SLEEP
0594 static int fdomain_resume(struct device *dev)
0595 {
0596 struct fdomain *fd = shost_priv(dev_get_drvdata(dev));
0597
0598 fdomain_reset(fd->base);
0599 return 0;
0600 }
0601
0602 static SIMPLE_DEV_PM_OPS(fdomain_pm_ops, NULL, fdomain_resume);
0603 #endif
0604
0605 MODULE_AUTHOR("Ondrej Zary, Rickard E. Faith");
0606 MODULE_DESCRIPTION("Future Domain TMC-16x0/TMC-3260 SCSI driver");
0607 MODULE_LICENSE("GPL");