aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2005-10-28 12:16:58 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-10-28 12:16:58 -0400
commit9be16a03928642f944915b8c05945fd87b7a15cb (patch)
tree85bc5a5886e9873a7f424012de3bd908a70ab115
parent5fadd053d9bb4345ec6f405d24db4e7eb49cf81e (diff)
parentcb650116a030dd5cf12f30651e29ceb990d42e4a (diff)
Merge branch 'sx8' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/misc-2.6
-rw-r--r--drivers/block/sx8.c51
1 files changed, 37 insertions, 14 deletions
diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c
index d57007b92f77..1ded3b433459 100644
--- a/drivers/block/sx8.c
+++ b/drivers/block/sx8.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * sx8.c: Driver for Promise SATA SX8 looks-like-I2O hardware 2 * sx8.c: Driver for Promise SATA SX8 looks-like-I2O hardware
3 * 3 *
4 * Copyright 2004 Red Hat, Inc. 4 * Copyright 2004-2005 Red Hat, Inc.
5 * 5 *
6 * Author/maintainer: Jeff Garzik <jgarzik@pobox.com> 6 * Author/maintainer: Jeff Garzik <jgarzik@pobox.com>
7 * 7 *
@@ -31,10 +31,6 @@
31#include <asm/semaphore.h> 31#include <asm/semaphore.h>
32#include <asm/uaccess.h> 32#include <asm/uaccess.h>
33 33
34MODULE_AUTHOR("Jeff Garzik");
35MODULE_LICENSE("GPL");
36MODULE_DESCRIPTION("Promise SATA SX8 block driver");
37
38#if 0 34#if 0
39#define CARM_DEBUG 35#define CARM_DEBUG
40#define CARM_VERBOSE_DEBUG 36#define CARM_VERBOSE_DEBUG
@@ -45,9 +41,35 @@ MODULE_DESCRIPTION("Promise SATA SX8 block driver");
45#undef CARM_NDEBUG 41#undef CARM_NDEBUG
46 42
47#define DRV_NAME "sx8" 43#define DRV_NAME "sx8"
48#define DRV_VERSION "0.8" 44#define DRV_VERSION "1.0"
49#define PFX DRV_NAME ": " 45#define PFX DRV_NAME ": "
50 46
47MODULE_AUTHOR("Jeff Garzik");
48MODULE_LICENSE("GPL");
49MODULE_DESCRIPTION("Promise SATA SX8 block driver");
50MODULE_VERSION(DRV_VERSION);
51
52/*
53 * SX8 hardware has a single message queue for all ATA ports.
54 * When this driver was written, the hardware (firmware?) would
55 * corrupt data eventually, if more than one request was outstanding.
56 * As one can imagine, having 8 ports bottlenecking on a single
57 * command hurts performance.
58 *
59 * Based on user reports, later versions of the hardware (firmware?)
60 * seem to be able to survive with more than one command queued.
61 *
62 * Therefore, we default to the safe option -- 1 command -- but
63 * allow the user to increase this.
64 *
65 * SX8 should be able to support up to ~60 queued commands (CARM_MAX_REQ),
66 * but problems seem to occur when you exceed ~30, even on newer hardware.
67 */
68static int max_queue = 1;
69module_param(max_queue, int, 0444);
70MODULE_PARM_DESC(max_queue, "Maximum number of queued commands. (min==1, max==30, safe==1)");
71
72
51#define NEXT_RESP(idx) ((idx + 1) % RMSG_Q_LEN) 73#define NEXT_RESP(idx) ((idx + 1) % RMSG_Q_LEN)
52 74
53/* 0xf is just arbitrary, non-zero noise; this is sorta like poisoning */ 75/* 0xf is just arbitrary, non-zero noise; this is sorta like poisoning */
@@ -90,12 +112,10 @@ enum {
90 112
91 /* command message queue limits */ 113 /* command message queue limits */
92 CARM_MAX_REQ = 64, /* max command msgs per host */ 114 CARM_MAX_REQ = 64, /* max command msgs per host */
93 CARM_MAX_Q = 1, /* one command at a time */
94 CARM_MSG_LOW_WATER = (CARM_MAX_REQ / 4), /* refill mark */ 115 CARM_MSG_LOW_WATER = (CARM_MAX_REQ / 4), /* refill mark */
95 116
96 /* S/G limits, host-wide and per-request */ 117 /* S/G limits, host-wide and per-request */
97 CARM_MAX_REQ_SG = 32, /* max s/g entries per request */ 118 CARM_MAX_REQ_SG = 32, /* max s/g entries per request */
98 CARM_SG_BOUNDARY = 0xffffUL, /* s/g segment boundary */
99 CARM_MAX_HOST_SG = 600, /* max s/g entries per host */ 119 CARM_MAX_HOST_SG = 600, /* max s/g entries per host */
100 CARM_SG_LOW_WATER = (CARM_MAX_HOST_SG / 4), /* re-fill mark */ 120 CARM_SG_LOW_WATER = (CARM_MAX_HOST_SG / 4), /* re-fill mark */
101 121
@@ -181,6 +201,10 @@ enum {
181 FL_DYN_MAJOR = (1 << 17), 201 FL_DYN_MAJOR = (1 << 17),
182}; 202};
183 203
204enum {
205 CARM_SG_BOUNDARY = 0xffffUL, /* s/g segment boundary */
206};
207
184enum scatter_gather_types { 208enum scatter_gather_types {
185 SGT_32BIT = 0, 209 SGT_32BIT = 0,
186 SGT_64BIT = 1, 210 SGT_64BIT = 1,
@@ -218,7 +242,6 @@ static const char *state_name[] = {
218 242
219struct carm_port { 243struct carm_port {
220 unsigned int port_no; 244 unsigned int port_no;
221 unsigned int n_queued;
222 struct gendisk *disk; 245 struct gendisk *disk;
223 struct carm_host *host; 246 struct carm_host *host;
224 247
@@ -448,7 +471,7 @@ static inline int carm_lookup_bucket(u32 msg_size)
448 for (i = 0; i < ARRAY_SIZE(msg_sizes); i++) 471 for (i = 0; i < ARRAY_SIZE(msg_sizes); i++)
449 if (msg_size <= msg_sizes[i]) 472 if (msg_size <= msg_sizes[i])
450 return i; 473 return i;
451 474
452 return -ENOENT; 475 return -ENOENT;
453} 476}
454 477
@@ -509,7 +532,7 @@ static struct carm_request *carm_get_request(struct carm_host *host)
509 if (host->hw_sg_used >= (CARM_MAX_HOST_SG - CARM_MAX_REQ_SG)) 532 if (host->hw_sg_used >= (CARM_MAX_HOST_SG - CARM_MAX_REQ_SG))
510 return NULL; 533 return NULL;
511 534
512 for (i = 0; i < CARM_MAX_Q; i++) 535 for (i = 0; i < max_queue; i++)
513 if ((host->msg_alloc & (1ULL << i)) == 0) { 536 if ((host->msg_alloc & (1ULL << i)) == 0) {
514 struct carm_request *crq = &host->req[i]; 537 struct carm_request *crq = &host->req[i];
515 crq->port = NULL; 538 crq->port = NULL;
@@ -521,14 +544,14 @@ static struct carm_request *carm_get_request(struct carm_host *host)
521 assert(host->n_msgs <= CARM_MAX_REQ); 544 assert(host->n_msgs <= CARM_MAX_REQ);
522 return crq; 545 return crq;
523 } 546 }
524 547
525 DPRINTK("no request available, returning NULL\n"); 548 DPRINTK("no request available, returning NULL\n");
526 return NULL; 549 return NULL;
527} 550}
528 551
529static int carm_put_request(struct carm_host *host, struct carm_request *crq) 552static int carm_put_request(struct carm_host *host, struct carm_request *crq)
530{ 553{
531 assert(crq->tag < CARM_MAX_Q); 554 assert(crq->tag < max_queue);
532 555
533 if (unlikely((host->msg_alloc & (1ULL << crq->tag)) == 0)) 556 if (unlikely((host->msg_alloc & (1ULL << crq->tag)) == 0))
534 return -EINVAL; /* tried to clear a tag that was not active */ 557 return -EINVAL; /* tried to clear a tag that was not active */
@@ -791,7 +814,7 @@ static inline void carm_end_rq(struct carm_host *host, struct carm_request *crq,
791 int is_ok) 814 int is_ok)
792{ 815{
793 carm_end_request_queued(host, crq, is_ok); 816 carm_end_request_queued(host, crq, is_ok);
794 if (CARM_MAX_Q == 1) 817 if (max_queue == 1)
795 carm_round_robin(host); 818 carm_round_robin(host);
796 else if ((host->n_msgs <= CARM_MSG_LOW_WATER) && 819 else if ((host->n_msgs <= CARM_MSG_LOW_WATER) &&
797 (host->hw_sg_used <= CARM_SG_LOW_WATER)) { 820 (host->hw_sg_used <= CARM_SG_LOW_WATER)) {