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 #include <linux/module.h>
0043 #include <linux/blkdev.h> /* to get disk capacity */
0044 #include <linux/kernel.h>
0045 #include <linux/string.h>
0046 #include <linux/init.h>
0047 #include <linux/interrupt.h>
0048 #include <linux/ioport.h>
0049 #include <linux/proc_fs.h>
0050 #include <linux/unistd.h>
0051 #include <linux/spinlock.h>
0052 #include <linux/stat.h>
0053
0054 #include <asm/io.h>
0055 #include <asm/irq.h>
0056 #include <asm/dma.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 "qlogicfas408.h"
0065
0066
0067 static int qlcfg5 = (XTALFREQ << 5);
0068 static int qlcfg6 = SYNCXFRPD;
0069 static int qlcfg7 = SYNCOFFST;
0070 static int qlcfg8 = (SLOWCABLE << 7) | (QL_ENABLE_PARITY << 4);
0071 static int qlcfg9 = ((XTALFREQ + 4) / 5);
0072 static int qlcfgc = (FASTCLK << 3) | (FASTSCSI << 4);
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082 static void ql_zap(struct qlogicfas408_priv *priv)
0083 {
0084 int x;
0085 int qbase = priv->qbase;
0086 int int_type = priv->int_type;
0087
0088 x = inb(qbase + 0xd);
0089 REG0;
0090 outb(3, qbase + 3);
0091 outb(2, qbase + 3);
0092 if (x & 0x80)
0093 REG1;
0094 }
0095
0096
0097
0098
0099
0100 static int ql_pdma(struct qlogicfas408_priv *priv, int phase, char *request,
0101 int reqlen)
0102 {
0103 int j;
0104 int qbase = priv->qbase;
0105 j = 0;
0106 if (phase & 1) {
0107 #if QL_TURBO_PDMA
0108 rtrc(4)
0109
0110 if (reqlen >= 128 && (inb(qbase + 8) & 2)) {
0111 insl(qbase + 4, request, 32);
0112 reqlen -= 128;
0113 request += 128;
0114 }
0115 while (reqlen >= 84 && !(j & 0xc0))
0116 if ((j = inb(qbase + 8)) & 4)
0117 {
0118 insl(qbase + 4, request, 21);
0119 reqlen -= 84;
0120 request += 84;
0121 }
0122 if (reqlen >= 44 && (inb(qbase + 8) & 8)) {
0123 insl(qbase + 4, request, 11);
0124 reqlen -= 44;
0125 request += 44;
0126 }
0127 #endif
0128
0129 rtrc(7)
0130 j = 0;
0131 while (reqlen && !((j & 0x10) && (j & 0xc0)))
0132 {
0133
0134 j &= 0xc0;
0135 while (reqlen && !((j = inb(qbase + 8)) & 0x10))
0136 {
0137 *request++ = inb(qbase + 4);
0138 reqlen--;
0139 }
0140 if (j & 0x10)
0141 j = inb(qbase + 8);
0142
0143 }
0144 } else {
0145 #if QL_TURBO_PDMA
0146 rtrc(4)
0147 if (reqlen >= 128 && inb(qbase + 8) & 0x10) {
0148 outsl(qbase + 4, request, 32);
0149 reqlen -= 128;
0150 request += 128;
0151 }
0152 while (reqlen >= 84 && !(j & 0xc0))
0153 if (!((j = inb(qbase + 8)) & 8)) {
0154 outsl(qbase + 4, request, 21);
0155 reqlen -= 84;
0156 request += 84;
0157 }
0158 if (reqlen >= 40 && !(inb(qbase + 8) & 4)) {
0159 outsl(qbase + 4, request, 10);
0160 reqlen -= 40;
0161 request += 40;
0162 }
0163 #endif
0164
0165 rtrc(7)
0166 j = 0;
0167 while (reqlen && !((j & 2) && (j & 0xc0))) {
0168
0169 while (reqlen && !((j = inb(qbase + 8)) & 2))
0170 {
0171 outb(*request++, qbase + 4);
0172 reqlen--;
0173 }
0174 if (j & 2)
0175 j = inb(qbase + 8);
0176 }
0177 }
0178
0179 return inb(qbase + 8) & 0xc0;
0180 }
0181
0182
0183
0184
0185
0186 static int ql_wai(struct qlogicfas408_priv *priv)
0187 {
0188 int k;
0189 int qbase = priv->qbase;
0190 unsigned long i;
0191
0192 k = 0;
0193 i = jiffies + WATCHDOG;
0194 while (time_before(jiffies, i) && !priv->qabort &&
0195 !((k = inb(qbase + 4)) & 0xe0)) {
0196 barrier();
0197 cpu_relax();
0198 }
0199 if (time_after_eq(jiffies, i))
0200 return (DID_TIME_OUT);
0201 if (priv->qabort)
0202 return (priv->qabort == 1 ? DID_ABORT : DID_RESET);
0203 if (k & 0x60)
0204 ql_zap(priv);
0205 if (k & 0x20)
0206 return (DID_PARITY);
0207 if (k & 0x40)
0208 return (DID_ERROR);
0209 return 0;
0210 }
0211
0212
0213
0214
0215
0216
0217 static void ql_icmd(struct scsi_cmnd *cmd)
0218 {
0219 struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
0220 int qbase = priv->qbase;
0221 int int_type = priv->int_type;
0222 unsigned int i;
0223
0224 priv->qabort = 0;
0225
0226 REG0;
0227
0228
0229 inb(qbase + 5);
0230 if (inb(qbase + 5))
0231 outb(2, qbase + 3);
0232 else if (inb(qbase + 7) & 0x1f)
0233 outb(1, qbase + 3);
0234 while (inb(qbase + 5));
0235 REG1;
0236 outb(1, qbase + 8);
0237 outb(0, qbase + 0xb);
0238 inb(qbase + 8);
0239 REG0;
0240 outb(0x40, qbase + 0xb);
0241
0242
0243 outb(qlcfgc, qbase + 0xc);
0244
0245 outb(0x40 | qlcfg8 | priv->qinitid, qbase + 8);
0246 outb(qlcfg7, qbase + 7);
0247 outb(qlcfg6, qbase + 6);
0248 outb(qlcfg5, qbase + 5);
0249 outb(qlcfg9 & 7, qbase + 9);
0250
0251 outb(scmd_id(cmd), qbase + 4);
0252
0253 for (i = 0; i < cmd->cmd_len; i++)
0254 outb(cmd->cmnd[i], qbase + 2);
0255
0256 priv->qlcmd = cmd;
0257 outb(0x41, qbase + 3);
0258 }
0259
0260
0261
0262
0263
0264 static void ql_pcmd(struct scsi_cmnd *cmd)
0265 {
0266 unsigned int i, j;
0267 unsigned long k;
0268 unsigned int status;
0269 unsigned int message;
0270 unsigned int phase;
0271 unsigned int reqlen;
0272 char *buf;
0273 struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
0274 int qbase = priv->qbase;
0275 int int_type = priv->int_type;
0276
0277 rtrc(1)
0278 j = inb(qbase + 6);
0279 i = inb(qbase + 5);
0280 if (i == 0x20) {
0281 set_host_byte(cmd, DID_NO_CONNECT);
0282 return;
0283 }
0284 i |= inb(qbase + 5);
0285 if (i != 0x18) {
0286 printk(KERN_ERR "Ql:Bad Interrupt status:%02x\n", i);
0287 ql_zap(priv);
0288 set_host_byte(cmd, DID_BAD_INTR);
0289 return;
0290 }
0291 j &= 7;
0292
0293
0294
0295
0296
0297
0298 if (j != 3 && j != 4) {
0299 printk(KERN_ERR "Ql:Bad sequence for command %d, int %02X, cmdleft = %d\n",
0300 j, i, inb(qbase + 7) & 0x1f);
0301 ql_zap(priv);
0302 set_host_byte(cmd, DID_ERROR);
0303 return;
0304 }
0305
0306 if (inb(qbase + 7) & 0x1f)
0307 outb(1, qbase + 3);
0308
0309 reqlen = scsi_bufflen(cmd);
0310
0311 if (reqlen && !((phase = inb(qbase + 4)) & 6)) {
0312 struct scatterlist *sg;
0313 rtrc(2)
0314 outb(reqlen, qbase);
0315 outb(reqlen >> 8, qbase + 1);
0316 outb(reqlen >> 16, qbase + 0xe);
0317 outb(0x90, qbase + 3);
0318
0319 REG1;
0320
0321 scsi_for_each_sg(cmd, sg, scsi_sg_count(cmd), i) {
0322 if (priv->qabort) {
0323 REG0;
0324 set_host_byte(cmd,
0325 priv->qabort == 1 ?
0326 DID_ABORT : DID_RESET);
0327 }
0328 buf = sg_virt(sg);
0329 if (ql_pdma(priv, phase, buf, sg->length))
0330 break;
0331 }
0332 REG0;
0333 rtrc(2);
0334
0335
0336
0337
0338 if ((k = ql_wai(priv))) {
0339 set_host_byte(cmd, k);
0340 return;
0341 }
0342 k = inb(qbase + 5);
0343 }
0344
0345
0346
0347
0348
0349 k = jiffies + WATCHDOG;
0350
0351 while (time_before(jiffies, k) && !priv->qabort &&
0352 !(inb(qbase + 4) & 6))
0353 cpu_relax();
0354
0355 if (time_after_eq(jiffies, k)) {
0356 ql_zap(priv);
0357 set_host_byte(cmd, DID_TIME_OUT);
0358 return;
0359 }
0360
0361
0362 while (inb(qbase + 5))
0363 cpu_relax();
0364
0365 if (priv->qabort) {
0366 set_host_byte(cmd,
0367 priv->qabort == 1 ? DID_ABORT : DID_RESET);
0368 return;
0369 }
0370
0371 outb(0x11, qbase + 3);
0372 if ((k = ql_wai(priv))) {
0373 set_host_byte(cmd, k);
0374 return;
0375 }
0376 i = inb(qbase + 5);
0377 j = inb(qbase + 7) & 0x1f;
0378 status = inb(qbase + 2);
0379 message = inb(qbase + 2);
0380
0381
0382
0383
0384
0385 if (!((i == 8 && j == 2) || (i == 0x10 && j == 1))) {
0386 printk(KERN_ERR "Ql:Error during status phase, int=%02X, %d bytes recd\n", i, j);
0387 set_host_byte(cmd, DID_ERROR);
0388 }
0389 outb(0x12, qbase + 3);
0390 rtrc(1);
0391 if ((k = ql_wai(priv))) {
0392 set_host_byte(cmd, k);
0393 return;
0394 }
0395
0396
0397
0398
0399
0400 i = inb(qbase + 5);
0401 while (!priv->qabort && ((i & 0x20) != 0x20)) {
0402 barrier();
0403 cpu_relax();
0404 i |= inb(qbase + 5);
0405 }
0406 rtrc(0);
0407
0408 if (priv->qabort) {
0409 set_host_byte(cmd,
0410 priv->qabort == 1 ? DID_ABORT : DID_RESET);
0411 return;
0412 }
0413
0414 set_host_byte(cmd, DID_OK);
0415 if (message != COMMAND_COMPLETE)
0416 scsi_msg_to_host_byte(cmd, message);
0417 set_status_byte(cmd, status);
0418 return;
0419 }
0420
0421
0422
0423
0424
0425 static void ql_ihandl(void *dev_id)
0426 {
0427 struct scsi_cmnd *icmd;
0428 struct Scsi_Host *host = dev_id;
0429 struct qlogicfas408_priv *priv = get_priv_by_host(host);
0430 int qbase = priv->qbase;
0431 REG0;
0432
0433 if (!(inb(qbase + 4) & 0x80))
0434 return;
0435
0436 if (priv->qlcmd == NULL) {
0437 int i;
0438 i = 16;
0439 while (i-- && inb(qbase + 5));
0440 return;
0441 }
0442 icmd = priv->qlcmd;
0443 ql_pcmd(icmd);
0444 priv->qlcmd = NULL;
0445
0446
0447
0448
0449 scsi_done(icmd);
0450 }
0451
0452 irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id)
0453 {
0454 unsigned long flags;
0455 struct Scsi_Host *host = dev_id;
0456
0457 spin_lock_irqsave(host->host_lock, flags);
0458 ql_ihandl(dev_id);
0459 spin_unlock_irqrestore(host->host_lock, flags);
0460 return IRQ_HANDLED;
0461 }
0462
0463
0464
0465
0466
0467 static int qlogicfas408_queuecommand_lck(struct scsi_cmnd *cmd)
0468 {
0469 void (*done)(struct scsi_cmnd *) = scsi_done;
0470 struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
0471
0472 set_host_byte(cmd, DID_OK);
0473 set_status_byte(cmd, SAM_STAT_GOOD);
0474 if (scmd_id(cmd) == priv->qinitid) {
0475 set_host_byte(cmd, DID_BAD_TARGET);
0476 done(cmd);
0477 return 0;
0478 }
0479
0480
0481 while (priv->qlcmd != NULL) {
0482 barrier();
0483 cpu_relax();
0484 }
0485 ql_icmd(cmd);
0486 return 0;
0487 }
0488
0489 DEF_SCSI_QCMD(qlogicfas408_queuecommand)
0490
0491
0492
0493
0494
0495 int qlogicfas408_biosparam(struct scsi_device *disk, struct block_device *dev,
0496 sector_t capacity, int ip[])
0497 {
0498
0499 ip[0] = 0x40;
0500 ip[1] = 0x20;
0501 ip[2] = (unsigned long) capacity / (ip[0] * ip[1]);
0502 if (ip[2] > 1024) {
0503 ip[0] = 0xff;
0504 ip[1] = 0x3f;
0505 ip[2] = (unsigned long) capacity / (ip[0] * ip[1]);
0506 #if 0
0507 if (ip[2] > 1023)
0508 ip[2] = 1023;
0509 #endif
0510 }
0511 return 0;
0512 }
0513
0514
0515
0516
0517
0518 int qlogicfas408_abort(struct scsi_cmnd *cmd)
0519 {
0520 struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
0521 priv->qabort = 1;
0522 ql_zap(priv);
0523 return SUCCESS;
0524 }
0525
0526
0527
0528
0529
0530
0531
0532 int qlogicfas408_host_reset(struct scsi_cmnd *cmd)
0533 {
0534 struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
0535 unsigned long flags;
0536
0537 priv->qabort = 2;
0538
0539 spin_lock_irqsave(cmd->device->host->host_lock, flags);
0540 ql_zap(priv);
0541 spin_unlock_irqrestore(cmd->device->host->host_lock, flags);
0542
0543 return SUCCESS;
0544 }
0545
0546
0547
0548
0549
0550 const char *qlogicfas408_info(struct Scsi_Host *host)
0551 {
0552 struct qlogicfas408_priv *priv = get_priv_by_host(host);
0553 return priv->qinfo;
0554 }
0555
0556
0557
0558
0559
0560 int qlogicfas408_get_chip_type(int qbase, int int_type)
0561 {
0562 REG1;
0563 return inb(qbase + 0xe) & 0xf8;
0564 }
0565
0566
0567
0568
0569
0570 void qlogicfas408_setup(int qbase, int id, int int_type)
0571 {
0572 outb(1, qbase + 8);
0573 REG0;
0574 outb(0x40 | qlcfg8 | id, qbase + 8);
0575 outb(qlcfg5, qbase + 5);
0576 outb(qlcfg9, qbase + 9);
0577
0578 #if QL_RESET_AT_START
0579 outb(3, qbase + 3);
0580
0581 REG1;
0582
0583 while (inb(qbase + 0xf) & 4)
0584 cpu_relax();
0585
0586 REG0;
0587 #endif
0588 }
0589
0590
0591
0592
0593
0594 int qlogicfas408_detect(int qbase, int int_type)
0595 {
0596 REG1;
0597 return (((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7) &&
0598 ((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7));
0599 }
0600
0601
0602
0603
0604
0605 void qlogicfas408_disable_ints(struct qlogicfas408_priv *priv)
0606 {
0607 int qbase = priv->qbase;
0608 int int_type = priv->int_type;
0609
0610 REG1;
0611 outb(0, qbase + 0xb);
0612 }
0613
0614
0615
0616
0617
0618 static int __init qlogicfas408_init(void)
0619 {
0620 return 0;
0621 }
0622
0623 static void __exit qlogicfas408_exit(void)
0624 {
0625
0626 }
0627
0628 MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
0629 MODULE_DESCRIPTION("Driver for the Qlogic FAS SCSI controllers");
0630 MODULE_LICENSE("GPL");
0631 module_init(qlogicfas408_init);
0632 module_exit(qlogicfas408_exit);
0633
0634 EXPORT_SYMBOL(qlogicfas408_info);
0635 EXPORT_SYMBOL(qlogicfas408_queuecommand);
0636 EXPORT_SYMBOL(qlogicfas408_abort);
0637 EXPORT_SYMBOL(qlogicfas408_host_reset);
0638 EXPORT_SYMBOL(qlogicfas408_biosparam);
0639 EXPORT_SYMBOL(qlogicfas408_ihandl);
0640 EXPORT_SYMBOL(qlogicfas408_get_chip_type);
0641 EXPORT_SYMBOL(qlogicfas408_setup);
0642 EXPORT_SYMBOL(qlogicfas408_detect);
0643 EXPORT_SYMBOL(qlogicfas408_disable_ints);
0644