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 #include <linux/blkdev.h>
0041 #include <linux/interrupt.h>
0042 #include <linux/module.h>
0043 #include <linux/kernel.h>
0044 #include <linux/types.h>
0045 #include <linux/string.h>
0046 #include <linux/ioport.h>
0047 #include <linux/proc_fs.h>
0048 #include <linux/stat.h>
0049 #include <linux/init.h>
0050 #include <linux/device.h>
0051 #include <linux/eisa.h>
0052 #include <linux/dma-mapping.h>
0053 #include <linux/gfp.h>
0054
0055 #include <asm/dma.h>
0056 #include <asm/io.h>
0057
0058 #include <scsi/scsi.h>
0059 #include <scsi/scsi_cmnd.h>
0060 #include <scsi/scsi_device.h>
0061 #include <scsi/scsi_eh.h>
0062 #include <scsi/scsi_host.h>
0063 #include <scsi/scsi_tcq.h>
0064 #include "aha1740.h"
0065
0066
0067
0068
0069
0070 #ifdef DEBUG
0071 #define DEB(x) x
0072 #else
0073 #define DEB(x)
0074 #endif
0075
0076 struct aha1740_hostdata {
0077 struct eisa_device *edev;
0078 unsigned int translation;
0079 unsigned int last_ecb_used;
0080 dma_addr_t ecb_dma_addr;
0081 struct ecb ecb[AHA1740_ECBS];
0082 };
0083
0084 struct aha1740_sg {
0085 struct aha1740_chain sg_chain[AHA1740_SCATTER];
0086 dma_addr_t sg_dma_addr;
0087 dma_addr_t buf_dma_addr;
0088 };
0089
0090 #define HOSTDATA(host) ((struct aha1740_hostdata *) &host->hostdata)
0091
0092 static inline struct ecb *ecb_dma_to_cpu (struct Scsi_Host *host,
0093 dma_addr_t dma)
0094 {
0095 struct aha1740_hostdata *hdata = HOSTDATA (host);
0096 dma_addr_t offset;
0097
0098 offset = dma - hdata->ecb_dma_addr;
0099
0100 return (struct ecb *)(((char *) hdata->ecb) + (unsigned int) offset);
0101 }
0102
0103 static inline dma_addr_t ecb_cpu_to_dma (struct Scsi_Host *host, void *cpu)
0104 {
0105 struct aha1740_hostdata *hdata = HOSTDATA (host);
0106 dma_addr_t offset;
0107
0108 offset = (char *) cpu - (char *) hdata->ecb;
0109
0110 return hdata->ecb_dma_addr + offset;
0111 }
0112
0113 static int aha1740_show_info(struct seq_file *m, struct Scsi_Host *shpnt)
0114 {
0115 struct aha1740_hostdata *host = HOSTDATA(shpnt);
0116 seq_printf(m, "aha174x at IO:%lx, IRQ %d, SLOT %d.\n"
0117 "Extended translation %sabled.\n",
0118 shpnt->io_port, shpnt->irq, host->edev->slot,
0119 host->translation ? "en" : "dis");
0120 return 0;
0121 }
0122
0123 static int aha1740_makecode(unchar *sense, unchar *status)
0124 {
0125 struct statusword
0126 {
0127 ushort don:1,
0128 du:1,
0129 :1, qf:1,
0130 sc:1,
0131 dor:1,
0132 ch:1,
0133 intr:1,
0134 asa:1,
0135 sns:1,
0136 :1, ini:1,
0137 me:1,
0138 :1, eca:1,
0139 :1;
0140 } status_word;
0141 int retval = DID_OK;
0142
0143 status_word = * (struct statusword *) status;
0144 #ifdef DEBUG
0145 printk("makecode from %x,%x,%x,%x %x,%x,%x,%x",
0146 status[0], status[1], status[2], status[3],
0147 sense[0], sense[1], sense[2], sense[3]);
0148 #endif
0149 if (!status_word.don) {
0150 if ( (status[1]&0x18) || status_word.sc ) {
0151
0152
0153 switch ( status[2] ) {
0154 case 0x12:
0155 if ( status_word.dor )
0156 retval=DID_ERROR;
0157
0158
0159 break;
0160 case 0x00:
0161
0162 break;
0163 case 0x11:
0164 case 0x21:
0165 retval=DID_TIME_OUT;
0166 break;
0167 case 0x0a:
0168 retval=DID_BAD_TARGET;
0169 break;
0170 case 0x04:
0171 case 0x05:
0172 retval=DID_ABORT;
0173
0174
0175 break;
0176 default:
0177 retval=DID_ERROR;
0178
0179
0180 }
0181 } else {
0182
0183 if ( status_word.qf ) {
0184 retval = DID_TIME_OUT;
0185
0186
0187 printk("aha1740.c: WARNING: AHA1740 queue overflow!\n");
0188 } else
0189 if ( status[0]&0x60 ) {
0190
0191 retval = DID_ERROR;
0192 }
0193
0194
0195
0196 }
0197 }
0198
0199 return status[3] | retval << 16;
0200 }
0201
0202 static int aha1740_test_port(unsigned int base)
0203 {
0204 if ( inb(PORTADR(base)) & PORTADDR_ENH )
0205 return 1;
0206
0207 printk("aha174x: Board detected, but not in enhanced mode, so disabled it.\n");
0208 return 0;
0209 }
0210
0211
0212 static irqreturn_t aha1740_intr_handle(int irq, void *dev_id)
0213 {
0214 struct Scsi_Host *host = (struct Scsi_Host *) dev_id;
0215 void (*my_done)(struct scsi_cmnd *);
0216 int errstatus, adapstat;
0217 int number_serviced;
0218 struct ecb *ecbptr;
0219 struct scsi_cmnd *SCtmp;
0220 unsigned int base;
0221 unsigned long flags;
0222 int handled = 0;
0223 struct aha1740_sg *sgptr;
0224 struct eisa_device *edev;
0225
0226 if (!host)
0227 panic("aha1740.c: Irq from unknown host!\n");
0228 spin_lock_irqsave(host->host_lock, flags);
0229 base = host->io_port;
0230 number_serviced = 0;
0231 edev = HOSTDATA(host)->edev;
0232
0233 while(inb(G2STAT(base)) & G2STAT_INTPEND) {
0234 handled = 1;
0235 DEB(printk("aha1740_intr top of loop.\n"));
0236 adapstat = inb(G2INTST(base));
0237 ecbptr = ecb_dma_to_cpu (host, inl(MBOXIN0(base)));
0238 outb(G2CNTRL_IRST,G2CNTRL(base));
0239
0240 switch ( adapstat & G2INTST_MASK ) {
0241 case G2INTST_CCBRETRY:
0242 case G2INTST_CCBERROR:
0243 case G2INTST_CCBGOOD:
0244
0245 outb(G2CNTRL_HRDY,G2CNTRL(base));
0246 if (!ecbptr) {
0247 printk("Aha1740 null ecbptr in interrupt (%x,%x,%x,%d)\n",
0248 inb(G2STAT(base)),adapstat,
0249 inb(G2INTST(base)), number_serviced++);
0250 continue;
0251 }
0252 SCtmp = ecbptr->SCpnt;
0253 if (!SCtmp) {
0254 printk("Aha1740 null SCtmp in interrupt (%x,%x,%x,%d)\n",
0255 inb(G2STAT(base)),adapstat,
0256 inb(G2INTST(base)), number_serviced++);
0257 continue;
0258 }
0259 sgptr = (struct aha1740_sg *) SCtmp->host_scribble;
0260 scsi_dma_unmap(SCtmp);
0261
0262
0263 dma_free_coherent (&edev->dev,
0264 sizeof (struct aha1740_sg),
0265 SCtmp->host_scribble,
0266 sgptr->sg_dma_addr);
0267
0268
0269
0270
0271
0272
0273 if ( (adapstat & G2INTST_MASK) == G2INTST_CCBERROR ) {
0274 memcpy_and_pad(SCtmp->sense_buffer,
0275 SCSI_SENSE_BUFFERSIZE,
0276 ecbptr->sense,
0277 sizeof(ecbptr->sense),
0278 0);
0279 errstatus = aha1740_makecode(ecbptr->sense,ecbptr->status);
0280 } else
0281 errstatus = 0;
0282 DEB(if (errstatus)
0283 printk("aha1740_intr_handle: returning %6x\n",
0284 errstatus));
0285 SCtmp->result = errstatus;
0286 my_done = ecbptr->done;
0287 memset(ecbptr,0,sizeof(struct ecb));
0288 if ( my_done )
0289 my_done(SCtmp);
0290 break;
0291
0292 case G2INTST_HARDFAIL:
0293 printk(KERN_ALERT "aha1740 hardware failure!\n");
0294 panic("aha1740.c");
0295
0296 case G2INTST_ASNEVENT:
0297 printk("aha1740 asynchronous event: %02x %02x %02x %02x %02x\n",
0298 adapstat,
0299 inb(MBOXIN0(base)),
0300 inb(MBOXIN1(base)),
0301 inb(MBOXIN2(base)),
0302 inb(MBOXIN3(base)));
0303
0304 outb(G2CNTRL_HRDY,G2CNTRL(base));
0305 break;
0306
0307 case G2INTST_CMDGOOD:
0308
0309 break;
0310
0311 case G2INTST_CMDERROR:
0312
0313 break;
0314 }
0315 number_serviced++;
0316 }
0317
0318 spin_unlock_irqrestore(host->host_lock, flags);
0319 return IRQ_RETVAL(handled);
0320 }
0321
0322 static int aha1740_queuecommand_lck(struct scsi_cmnd *SCpnt)
0323 {
0324 void (*done)(struct scsi_cmnd *) = scsi_done;
0325 unchar direction;
0326 unchar *cmd = (unchar *) SCpnt->cmnd;
0327 unchar target = scmd_id(SCpnt);
0328 struct aha1740_hostdata *host = HOSTDATA(SCpnt->device->host);
0329 unsigned long flags;
0330 dma_addr_t sg_dma;
0331 struct aha1740_sg *sgptr;
0332 int ecbno, nseg;
0333 DEB(int i);
0334
0335 if(*cmd == REQUEST_SENSE) {
0336 SCpnt->result = 0;
0337 done(SCpnt);
0338 return 0;
0339 }
0340
0341 #ifdef DEBUG
0342 if (*cmd == READ_10 || *cmd == WRITE_10)
0343 i = xscsi2int(cmd+2);
0344 else if (*cmd == READ_6 || *cmd == WRITE_6)
0345 i = scsi2int(cmd+2);
0346 else
0347 i = -1;
0348 printk("aha1740_queuecommand: dev %d cmd %02x pos %d len %d ",
0349 target, *cmd, i, bufflen);
0350 printk("scsi cmd:");
0351 for (i = 0; i < SCpnt->cmd_len; i++) printk("%02x ", cmd[i]);
0352 printk("\n");
0353 #endif
0354
0355
0356 spin_lock_irqsave(SCpnt->device->host->host_lock, flags);
0357 ecbno = host->last_ecb_used + 1;
0358 if (ecbno >= AHA1740_ECBS)
0359 ecbno = 0;
0360 do {
0361 if (!host->ecb[ecbno].cmdw)
0362 break;
0363 ecbno++;
0364 if (ecbno >= AHA1740_ECBS)
0365 ecbno = 0;
0366 } while (ecbno != host->last_ecb_used);
0367
0368 if (host->ecb[ecbno].cmdw)
0369 panic("Unable to find empty ecb for aha1740.\n");
0370
0371 host->ecb[ecbno].cmdw = AHA1740CMD_INIT;
0372
0373
0374 host->last_ecb_used = ecbno;
0375 spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags);
0376
0377 #ifdef DEBUG
0378 printk("Sending command (%d %x)...", ecbno, done);
0379 #endif
0380
0381 host->ecb[ecbno].cdblen = SCpnt->cmd_len;
0382
0383
0384
0385 direction = 0;
0386 if (*cmd == READ_10 || *cmd == READ_6)
0387 direction = 1;
0388 else if (*cmd == WRITE_10 || *cmd == WRITE_6)
0389 direction = 0;
0390
0391 memcpy(host->ecb[ecbno].cdb, cmd, SCpnt->cmd_len);
0392
0393 SCpnt->host_scribble = dma_alloc_coherent (&host->edev->dev,
0394 sizeof (struct aha1740_sg),
0395 &sg_dma, GFP_ATOMIC);
0396 if(SCpnt->host_scribble == NULL) {
0397 printk(KERN_WARNING "aha1740: out of memory in queuecommand!\n");
0398 return 1;
0399 }
0400 sgptr = (struct aha1740_sg *) SCpnt->host_scribble;
0401 sgptr->sg_dma_addr = sg_dma;
0402
0403 nseg = scsi_dma_map(SCpnt);
0404 BUG_ON(nseg < 0);
0405 if (nseg) {
0406 struct scatterlist *sg;
0407 struct aha1740_chain * cptr;
0408 int i;
0409 DEB(unsigned char * ptr);
0410
0411 host->ecb[ecbno].sg = 1;
0412
0413 cptr = sgptr->sg_chain;
0414 scsi_for_each_sg(SCpnt, sg, nseg, i) {
0415 cptr[i].datalen = sg_dma_len (sg);
0416 cptr[i].dataptr = sg_dma_address (sg);
0417 }
0418 host->ecb[ecbno].datalen = nseg * sizeof(struct aha1740_chain);
0419 host->ecb[ecbno].dataptr = sg_dma;
0420 #ifdef DEBUG
0421 printk("cptr %x: ",cptr);
0422 ptr = (unsigned char *) cptr;
0423 for(i=0;i<24;i++) printk("%02x ", ptr[i]);
0424 #endif
0425 } else {
0426 host->ecb[ecbno].datalen = 0;
0427 host->ecb[ecbno].dataptr = 0;
0428 }
0429 host->ecb[ecbno].lun = SCpnt->device->lun;
0430 host->ecb[ecbno].ses = 1;
0431 host->ecb[ecbno].dir = direction;
0432 host->ecb[ecbno].ars = 1;
0433 host->ecb[ecbno].senselen = 12;
0434 host->ecb[ecbno].senseptr = ecb_cpu_to_dma (SCpnt->device->host,
0435 host->ecb[ecbno].sense);
0436 host->ecb[ecbno].statusptr = ecb_cpu_to_dma (SCpnt->device->host,
0437 host->ecb[ecbno].status);
0438 host->ecb[ecbno].done = done;
0439 host->ecb[ecbno].SCpnt = SCpnt;
0440 #ifdef DEBUG
0441 {
0442 int i;
0443 printk("aha1740_command: sending.. ");
0444 for (i = 0; i < sizeof(host->ecb[ecbno]) - 10; i++)
0445 printk("%02x ", ((unchar *)&host->ecb[ecbno])[i]);
0446 }
0447 printk("\n");
0448 #endif
0449 if (done) {
0450
0451
0452
0453
0454
0455
0456
0457
0458
0459
0460
0461
0462 #define LOOPCNT_WARN 10
0463 #define LOOPCNT_MAX 1000000
0464 int loopcnt;
0465 unsigned int base = SCpnt->device->host->io_port;
0466 DEB(printk("aha1740[%d] critical section\n",ecbno));
0467
0468 spin_lock_irqsave(SCpnt->device->host->host_lock, flags);
0469 for (loopcnt = 0; ; loopcnt++) {
0470 if (inb(G2STAT(base)) & G2STAT_MBXOUT) break;
0471 if (loopcnt == LOOPCNT_WARN) {
0472 printk("aha1740[%d]_mbxout wait!\n",ecbno);
0473 }
0474 if (loopcnt == LOOPCNT_MAX)
0475 panic("aha1740.c: mbxout busy!\n");
0476 }
0477 outl (ecb_cpu_to_dma (SCpnt->device->host, host->ecb + ecbno),
0478 MBOXOUT0(base));
0479 for (loopcnt = 0; ; loopcnt++) {
0480 if (! (inb(G2STAT(base)) & G2STAT_BUSY)) break;
0481 if (loopcnt == LOOPCNT_WARN) {
0482 printk("aha1740[%d]_attn wait!\n",ecbno);
0483 }
0484 if (loopcnt == LOOPCNT_MAX)
0485 panic("aha1740.c: attn wait failed!\n");
0486 }
0487 outb(ATTN_START | (target & 7), ATTN(base));
0488 spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags);
0489 DEB(printk("aha1740[%d] request queued.\n",ecbno));
0490 } else
0491 printk(KERN_ALERT "aha1740_queuecommand: done can't be NULL\n");
0492 return 0;
0493 }
0494
0495 static DEF_SCSI_QCMD(aha1740_queuecommand)
0496
0497
0498
0499
0500 static void aha1740_getconfig(unsigned int base, unsigned int *irq_level,
0501 unsigned int *irq_type,
0502 unsigned int *translation)
0503 {
0504 static int intab[] = { 9, 10, 11, 12, 0, 14, 15, 0 };
0505
0506 *irq_level = intab[inb(INTDEF(base)) & 0x7];
0507 *irq_type = (inb(INTDEF(base)) & 0x8) >> 3;
0508 *translation = inb(RESV1(base)) & 0x1;
0509 outb(inb(INTDEF(base)) | 0x10, INTDEF(base));
0510 }
0511
0512 static int aha1740_biosparam(struct scsi_device *sdev,
0513 struct block_device *dev,
0514 sector_t capacity, int* ip)
0515 {
0516 int size = capacity;
0517 int extended = HOSTDATA(sdev->host)->translation;
0518
0519 DEB(printk("aha1740_biosparam\n"));
0520 if (extended && (ip[2] > 1024)) {
0521 ip[0] = 255;
0522 ip[1] = 63;
0523 ip[2] = size / (255 * 63);
0524 } else {
0525 ip[0] = 64;
0526 ip[1] = 32;
0527 ip[2] = size >> 11;
0528 }
0529 return 0;
0530 }
0531
0532 static int aha1740_eh_abort_handler (struct scsi_cmnd *dummy)
0533 {
0534
0535
0536
0537
0538
0539
0540
0541
0542
0543 return SUCCESS;
0544 }
0545
0546 static struct scsi_host_template aha1740_template = {
0547 .module = THIS_MODULE,
0548 .proc_name = "aha1740",
0549 .show_info = aha1740_show_info,
0550 .name = "Adaptec 174x (EISA)",
0551 .queuecommand = aha1740_queuecommand,
0552 .bios_param = aha1740_biosparam,
0553 .can_queue = AHA1740_ECBS,
0554 .this_id = 7,
0555 .sg_tablesize = AHA1740_SCATTER,
0556 .eh_abort_handler = aha1740_eh_abort_handler,
0557 };
0558
0559 static int aha1740_probe (struct device *dev)
0560 {
0561 int slotbase, rc;
0562 unsigned int irq_level, irq_type, translation;
0563 struct Scsi_Host *shpnt;
0564 struct aha1740_hostdata *host;
0565 struct eisa_device *edev = to_eisa_device (dev);
0566
0567 DEB(printk("aha1740_probe: \n"));
0568
0569 slotbase = edev->base_addr + EISA_VENDOR_ID_OFFSET;
0570 if (!request_region(slotbase, SLOTSIZE, "aha1740"))
0571 return -EBUSY;
0572 if (!aha1740_test_port(slotbase))
0573 goto err_release_region;
0574 aha1740_getconfig(slotbase,&irq_level,&irq_type,&translation);
0575 if ((inb(G2STAT(slotbase)) &
0576 (G2STAT_MBXOUT|G2STAT_BUSY)) != G2STAT_MBXOUT) {
0577
0578 outb(G2CNTRL_HRST, G2CNTRL(slotbase));
0579 outb(0, G2CNTRL(slotbase));
0580 }
0581 printk(KERN_INFO "Configuring slot %d at IO:%x, IRQ %u (%s)\n",
0582 edev->slot, slotbase, irq_level, irq_type ? "edge" : "level");
0583 printk(KERN_INFO "aha174x: Extended translation %sabled.\n",
0584 translation ? "en" : "dis");
0585 shpnt = scsi_host_alloc(&aha1740_template,
0586 sizeof(struct aha1740_hostdata));
0587 if(shpnt == NULL)
0588 goto err_release_region;
0589
0590 shpnt->base = 0;
0591 shpnt->io_port = slotbase;
0592 shpnt->n_io_port = SLOTSIZE;
0593 shpnt->irq = irq_level;
0594 shpnt->dma_channel = 0xff;
0595 host = HOSTDATA(shpnt);
0596 host->edev = edev;
0597 host->translation = translation;
0598 host->ecb_dma_addr = dma_map_single (&edev->dev, host->ecb,
0599 sizeof (host->ecb),
0600 DMA_BIDIRECTIONAL);
0601 if (!host->ecb_dma_addr) {
0602 printk (KERN_ERR "aha1740_probe: Couldn't map ECB, giving up\n");
0603 goto err_host_put;
0604 }
0605
0606 DEB(printk("aha1740_probe: enable interrupt channel %d\n",irq_level));
0607 if (request_irq(irq_level,aha1740_intr_handle,irq_type ? 0 : IRQF_SHARED,
0608 "aha1740",shpnt)) {
0609 printk(KERN_ERR "aha1740_probe: Unable to allocate IRQ %d.\n",
0610 irq_level);
0611 goto err_unmap;
0612 }
0613
0614 eisa_set_drvdata (edev, shpnt);
0615
0616 rc = scsi_add_host (shpnt, dev);
0617 if (rc)
0618 goto err_irq;
0619
0620 scsi_scan_host (shpnt);
0621 return 0;
0622
0623 err_irq:
0624 free_irq(irq_level, shpnt);
0625 err_unmap:
0626 dma_unmap_single (&edev->dev, host->ecb_dma_addr,
0627 sizeof (host->ecb), DMA_BIDIRECTIONAL);
0628 err_host_put:
0629 scsi_host_put (shpnt);
0630 err_release_region:
0631 release_region(slotbase, SLOTSIZE);
0632
0633 return -ENODEV;
0634 }
0635
0636 static int aha1740_remove (struct device *dev)
0637 {
0638 struct Scsi_Host *shpnt = dev_get_drvdata(dev);
0639 struct aha1740_hostdata *host = HOSTDATA (shpnt);
0640
0641 scsi_remove_host(shpnt);
0642
0643 free_irq (shpnt->irq, shpnt);
0644 dma_unmap_single (dev, host->ecb_dma_addr,
0645 sizeof (host->ecb), DMA_BIDIRECTIONAL);
0646 release_region (shpnt->io_port, SLOTSIZE);
0647
0648 scsi_host_put (shpnt);
0649
0650 return 0;
0651 }
0652
0653 static struct eisa_device_id aha1740_ids[] = {
0654 { "ADP0000" },
0655 { "ADP0001" },
0656 { "ADP0002" },
0657 { "ADP0400" },
0658 { "" }
0659 };
0660 MODULE_DEVICE_TABLE(eisa, aha1740_ids);
0661
0662 static struct eisa_driver aha1740_driver = {
0663 .id_table = aha1740_ids,
0664 .driver = {
0665 .name = "aha1740",
0666 .probe = aha1740_probe,
0667 .remove = aha1740_remove,
0668 },
0669 };
0670
0671 static __init int aha1740_init (void)
0672 {
0673 return eisa_driver_register (&aha1740_driver);
0674 }
0675
0676 static __exit void aha1740_exit (void)
0677 {
0678 eisa_driver_unregister (&aha1740_driver);
0679 }
0680
0681 module_init (aha1740_init);
0682 module_exit (aha1740_exit);
0683
0684 MODULE_LICENSE("GPL");