From a5d8421b2f03e46f02cc02066b186fdbc0f590a6 Mon Sep 17 00:00:00 2001 From: peter fuerst Date: Mon, 12 Feb 2007 15:20:15 +0100 Subject: [SCSI] wd33c93: Fast SCSI with WD33C93B Attached are patches, which help to utilize more of the WD33C93B SCSI controller's capabilities. 1) Added/changed all the necessary code to enable Burst Mode DMA. Only Single Byte DMA was used before. 2) Added/changed all the necessary code to enable Fast-10 SCSI transfers. 3) The original driver inadvertently used a transfer period of 1000-800ns (the lowest possible transfer rate) for asynchronous data transfers, instead of the (configurable) default period intended for this purpose, if the target responded to a SDTR not with a Reject-message, but with a zero-SDTR. This issue was fixed. Moreover, in case of a Reject the driver used the default-period's initialization-value instead of its (maybe smaller) current value. The missing assignment was added. 4) The driver's commandline- and proc-file-interface was augmented to handle the new options properly. The WD33C93 manual, found at http://www.datasheet.in/datasheet-html/W/D/3/WD33C93B_WesternDigital.pdf.html, was very helpful. Signed-off-by: peter fuerst Signed-off-by: James Bottomley --- drivers/scsi/wd33c93.c | 321 +++++++++++++++++++++++++++++++++++++------------ drivers/scsi/wd33c93.h | 6 + 2 files changed, 248 insertions(+), 79 deletions(-) diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c index 835751600e93..fa4e08e508ad 100644 --- a/drivers/scsi/wd33c93.c +++ b/drivers/scsi/wd33c93.c @@ -69,6 +69,11 @@ * Added support for pre -A chips, which don't have advanced features * and will generate CSR_RESEL rather than CSR_RESEL_AM. * Richard Hirst August 2000 + * + * Added support for Burst Mode DMA and Fast SCSI. Enabled the use of + * default_sx_per for asynchronous data transfers. Added adjustment + * of transfer periods in sx_table to the actual input-clock. + * peter fuerst February 2007 */ #include @@ -86,9 +91,11 @@ #include "wd33c93.h" +#define optimum_sx_per(hostdata) (hostdata)->sx_table[1].period_ns + -#define WD33C93_VERSION "1.26" -#define WD33C93_DATE "22/Feb/2003" +#define WD33C93_VERSION "1.26++" +#define WD33C93_DATE "10/Feb/2007" MODULE_AUTHOR("John Shifflett"); MODULE_DESCRIPTION("Generic WD33C93 SCSI driver"); @@ -122,6 +129,13 @@ MODULE_LICENSE("GPL"); * defines in wd33c93.h * - clock:x -x = clock input in MHz for WD33c93 chip. Normal values * would be from 8 through 20. Default is 8. + * - burst:x -x = 1 to use Burst Mode (or Demand-Mode) DMA, x = 0 to use + * Single Byte DMA, which is the default. Argument is + * optional - if not present, same as "burst:1". + * - fast:x -x = 1 to enable Fast SCSI, which is only effective with + * input-clock divisor 4 (WD33C93_FS_16_20), x = 0 to disable + * it, which is the default. Argument is optional - if not + * present, same as "fast:1". * - next -No argument. Used to separate blocks of keywords when * there's more than one host adapter in the system. * @@ -148,7 +162,7 @@ MODULE_LICENSE("GPL"); */ /* Normally, no defaults are specified */ -static char *setup_args[] = { "", "", "", "", "", "", "", "", "" }; +static char *setup_args[] = { "", "", "", "", "", "", "", "", "", "" }; static char *setup_strings; module_param(setup_strings, charp, 0); @@ -298,20 +312,8 @@ read_1_byte(const wd33c93_regs regs) return x; } -static struct sx_period sx_table[] = { - {1, 0x20}, - {252, 0x20}, - {376, 0x30}, - {500, 0x40}, - {624, 0x50}, - {752, 0x60}, - {876, 0x70}, - {1000, 0x00}, - {0, 0} -}; - static int -round_period(unsigned int period) +round_period(unsigned int period, const struct sx_period *sx_table) { int x; @@ -324,17 +326,49 @@ round_period(unsigned int period) return 7; } +/* + * Calculate Synchronous Transfer Register value from SDTR code. + */ static uchar -calc_sync_xfer(unsigned int period, unsigned int offset) +calc_sync_xfer(unsigned int period, unsigned int offset, unsigned int fast, + const struct sx_period *sx_table) { + /* When doing Fast SCSI synchronous data transfers, the corresponding + * value in 'sx_table' is two times the actually used transfer period. + */ uchar result; + if (offset && fast) { + fast = STR_FSS; + period *= 2; + } else { + fast = 0; + } period *= 4; /* convert SDTR code to ns */ - result = sx_table[round_period(period)].reg_value; + result = sx_table[round_period(period,sx_table)].reg_value; result |= (offset < OPTIMUM_SX_OFF) ? offset : OPTIMUM_SX_OFF; + result |= fast; return result; } +/* + * Calculate SDTR code bytes [3],[4] from period and offset. + */ +static inline void +calc_sync_msg(unsigned int period, unsigned int offset, unsigned int fast, + uchar msg[2]) +{ + /* 'period' is a "normal"-mode value, like the ones in 'sx_table'. The + * actually used transfer period for Fast SCSI synchronous data + * transfers is half that value. + */ + period /= 4; + if (offset && fast) + period /= 2; + msg[0] = period; + msg[1] = offset; +} + int wd33c93_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) @@ -632,7 +666,7 @@ wd33c93_execute(struct Scsi_Host *instance) write_wd33c93_count(regs, cmd->SCp.this_residual); write_wd33c93(regs, WD_CONTROL, - CTRL_IDI | CTRL_EDI | CTRL_DMA); + CTRL_IDI | CTRL_EDI | hostdata->dma_mode); hostdata->dma = D_DMA_RUNNING; } } else @@ -712,6 +746,8 @@ transfer_bytes(const wd33c93_regs regs, struct scsi_cmnd *cmd, cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) + cmd->SCp.buffer->offset; } + if (!cmd->SCp.this_residual) /* avoid bogus setups */ + return; write_wd33c93(regs, WD_SYNCHRONOUS_TRANSFER, hostdata->sync_xfer[cmd->device->id]); @@ -744,7 +780,7 @@ transfer_bytes(const wd33c93_regs regs, struct scsi_cmnd *cmd, #ifdef PROC_STATISTICS hostdata->dma_cnt++; #endif - write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_DMA); + write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | hostdata->dma_mode); write_wd33c93_count(regs, cmd->SCp.this_residual); if ((hostdata->level2 >= L2_DATA) || @@ -862,9 +898,6 @@ wd33c93_intr(struct Scsi_Host *instance) hostdata->outgoing_msg[0] |= 0x40; if (hostdata->sync_stat[cmd->device->id] == SS_FIRST) { -#ifdef SYNC_DEBUG - printk(" sending SDTR "); -#endif hostdata->sync_stat[cmd->device->id] = SS_WAITING; @@ -878,14 +911,20 @@ wd33c93_intr(struct Scsi_Host *instance) hostdata->outgoing_msg[2] = 3; hostdata->outgoing_msg[3] = EXTENDED_SDTR; if (hostdata->no_sync & (1 << cmd->device->id)) { - hostdata->outgoing_msg[4] = - hostdata->default_sx_per / 4; - hostdata->outgoing_msg[5] = 0; + calc_sync_msg(hostdata->default_sx_per, 0, + 0, hostdata->outgoing_msg + 4); } else { - hostdata->outgoing_msg[4] = OPTIMUM_SX_PER / 4; - hostdata->outgoing_msg[5] = OPTIMUM_SX_OFF; + calc_sync_msg(optimum_sx_per(hostdata), + OPTIMUM_SX_OFF, + hostdata->fast, + hostdata->outgoing_msg + 4); } hostdata->outgoing_len = 6; +#ifdef SYNC_DEBUG + ucp = hostdata->outgoing_msg + 1; + printk(" sending SDTR %02x03%02x%02x%02x ", + ucp[0], ucp[2], ucp[3], ucp[4]); +#endif } else hostdata->outgoing_len = 1; @@ -1001,8 +1040,13 @@ wd33c93_intr(struct Scsi_Host *instance) #ifdef SYNC_DEBUG printk("-REJ-"); #endif - if (hostdata->sync_stat[cmd->device->id] == SS_WAITING) + if (hostdata->sync_stat[cmd->device->id] == SS_WAITING) { hostdata->sync_stat[cmd->device->id] = SS_SET; + /* we want default_sx_per, not DEFAULT_SX_PER */ + hostdata->sync_xfer[cmd->device->id] = + calc_sync_xfer(hostdata->default_sx_per + / 4, 0, 0, hostdata->sx_table); + } write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK); hostdata->state = S_CONNECTED; break; @@ -1022,7 +1066,10 @@ wd33c93_intr(struct Scsi_Host *instance) switch (ucp[2]) { /* what's the EXTENDED code? */ case EXTENDED_SDTR: - id = calc_sync_xfer(ucp[3], ucp[4]); + /* default to default async period */ + id = calc_sync_xfer(hostdata-> + default_sx_per / 4, 0, + 0, hostdata->sx_table); if (hostdata->sync_stat[cmd->device->id] != SS_WAITING) { @@ -1041,20 +1088,22 @@ wd33c93_intr(struct Scsi_Host *instance) hostdata->outgoing_msg[1] = 3; hostdata->outgoing_msg[2] = EXTENDED_SDTR; - hostdata->outgoing_msg[3] = - hostdata->default_sx_per / - 4; - hostdata->outgoing_msg[4] = 0; + calc_sync_msg(hostdata-> + default_sx_per, 0, + 0, hostdata->outgoing_msg + 3); hostdata->outgoing_len = 5; - hostdata->sync_xfer[cmd->device->id] = - calc_sync_xfer(hostdata-> - default_sx_per - / 4, 0); } else { - hostdata->sync_xfer[cmd->device->id] = id; + if (ucp[4]) /* well, sync transfer */ + id = calc_sync_xfer(ucp[3], ucp[4], + hostdata->fast, + hostdata->sx_table); + else if (ucp[3]) /* very unlikely... */ + id = calc_sync_xfer(ucp[3], ucp[4], + 0, hostdata->sx_table); } + hostdata->sync_xfer[cmd->device->id] = id; #ifdef SYNC_DEBUG - printk("sync_xfer=%02x", + printk(" sync_xfer=%02x\n", hostdata->sync_xfer[cmd->device->id]); #endif hostdata->sync_stat[cmd->device->id] = @@ -1486,7 +1535,7 @@ reset_wd33c93(struct Scsi_Host *instance) write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); write_wd33c93(regs, WD_SYNCHRONOUS_TRANSFER, calc_sync_xfer(hostdata->default_sx_per / 4, - DEFAULT_SX_OFF)); + DEFAULT_SX_OFF, 0, hostdata->sx_table)); write_wd33c93(regs, WD_COMMAND, WD_CMD_RESET); @@ -1512,6 +1561,9 @@ reset_wd33c93(struct Scsi_Host *instance) } else hostdata->chip = C_UNKNOWN_CHIP; + if (hostdata->chip != C_WD33C93B) /* Fast SCSI unavailable */ + hostdata->fast = 0; + write_wd33c93(regs, WD_TIMEOUT_PERIOD, TIMEOUT_PERIOD_VALUE); write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); } @@ -1533,7 +1585,8 @@ wd33c93_host_reset(struct scsi_cmnd * SCpnt) for (i = 0; i < 8; i++) { hostdata->busy[i] = 0; hostdata->sync_xfer[i] = - calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF); + calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF, + 0, hostdata->sx_table); hostdata->sync_stat[i] = SS_UNSET; /* using default sync values */ } hostdata->input_Q = NULL; @@ -1782,6 +1835,98 @@ check_setup_args(char *key, int *flags, int *val, char *buf) return ++x; } +/* + * Calculate internal data-transfer-clock cycle from input-clock + * frequency (/MHz) and fill 'sx_table'. + * + * The original driver used to rely on a fixed sx_table, containing periods + * for (only) the lower limits of the respective input-clock-frequency ranges + * (8-10/12-15/16-20 MHz). Although it seems, that no problems ocurred with + * this setting so far, it might be desirable to adjust the transfer periods + * closer to the really attached, possibly 25% higher, input-clock, since + * - the wd33c93 may really use a significant shorter period, than it has + * negotiated (eg. thrashing the target, which expects 4/8MHz, with 5/10MHz + * instead). + * - the wd33c93 may ask the target for a lower transfer rate, than the target + * is capable of (eg. negotiating for an assumed minimum of 252ns instead of + * possible 200ns, which indeed shows up in tests as an approx. 10% lower + * transfer rate). + */ +static inline unsigned int +round_4(unsigned int x) +{ + switch (x & 3) { + case 1: --x; + break; + case 2: ++x; + case 3: ++x; + } + return x; +} + +static void +calc_sx_table(unsigned int mhz, struct sx_period sx_table[9]) +{ + unsigned int d, i; + if (mhz < 11) + d = 2; /* divisor for 8-10 MHz input-clock */ + else if (mhz < 16) + d = 3; /* divisor for 12-15 MHz input-clock */ + else + d = 4; /* divisor for 16-20 MHz input-clock */ + + d = (100000 * d) / 2 / mhz; /* 100 x DTCC / nanosec */ + + sx_table[0].period_ns = 1; + sx_table[0].reg_value = 0x20; + for (i = 1; i < 8; i++) { + sx_table[i].period_ns = round_4((i+1)*d / 100); + sx_table[i].reg_value = (i+1)*0x10; + } + sx_table[7].reg_value = 0; + sx_table[8].period_ns = 0; + sx_table[8].reg_value = 0; +} + +/* + * check and, maybe, map an init- or "clock:"- argument. + */ +static uchar +set_clk_freq(int freq, int *mhz) +{ + int x = freq; + if (WD33C93_FS_8_10 == freq) + freq = 8; + else if (WD33C93_FS_12_15 == freq) + freq = 12; + else if (WD33C93_FS_16_20 == freq) + freq = 16; + else if (freq > 7 && freq < 11) + x = WD33C93_FS_8_10; + else if (freq > 11 && freq < 16) + x = WD33C93_FS_12_15; + else if (freq > 15 && freq < 21) + x = WD33C93_FS_16_20; + else { + /* Hmm, wouldn't it be safer to assume highest freq here? */ + x = WD33C93_FS_8_10; + freq = 8; + } + *mhz = freq; + return x; +} + +/* + * to be used with the resync: fast: ... options + */ +static inline void set_resync ( struct WD33C93_hostdata *hd, int mask ) +{ + int i; + for (i = 0; i < 8; i++) + if (mask & (1 << i)) + hd->sync_stat[i] = SS_UNSET; +} + void wd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs, dma_setup_t setup, dma_stop_t stop, int clock_freq) @@ -1798,7 +1943,8 @@ wd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs, hostdata = (struct WD33C93_hostdata *) instance->hostdata; hostdata->regs = regs; - hostdata->clock_freq = clock_freq; + hostdata->clock_freq = set_clk_freq(clock_freq, &i); + calc_sx_table(i, hostdata->sx_table); hostdata->dma_setup = setup; hostdata->dma_stop = stop; hostdata->dma_bounce_buffer = NULL; @@ -1806,7 +1952,8 @@ wd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs, for (i = 0; i < 8; i++) { hostdata->busy[i] = 0; hostdata->sync_xfer[i] = - calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF); + calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF, + 0, hostdata->sx_table); hostdata->sync_stat[i] = SS_UNSET; /* using default sync values */ #ifdef PROC_STATISTICS hostdata->cmd_cnt[i] = 0; @@ -1828,6 +1975,8 @@ wd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs, hostdata->default_sx_per = DEFAULT_SX_PER; hostdata->no_sync = 0xff; /* sync defaults to off */ hostdata->no_dma = 0; /* default is DMA enabled */ + hostdata->fast = 0; /* default is Fast SCSI transfers disabled */ + hostdata->dma_mode = CTRL_DMA; /* default is Single Byte DMA */ #ifdef PROC_INTERFACE hostdata->proc = PR_VERSION | PR_INFO | PR_STATISTICS | @@ -1839,6 +1988,11 @@ wd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs, #endif #endif + if (check_setup_args("clock", &flags, &val, buf)) { + hostdata->clock_freq = set_clk_freq(val, &val); + calc_sx_table(val, hostdata->sx_table); + } + if (check_setup_args("nosync", &flags, &val, buf)) hostdata->no_sync = val; @@ -1847,7 +2001,8 @@ wd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs, if (check_setup_args("period", &flags, &val, buf)) hostdata->default_sx_per = - sx_table[round_period((unsigned int) val)].period_ns; + hostdata->sx_table[round_period((unsigned int) val, + hostdata->sx_table)].period_ns; if (check_setup_args("disconnect", &flags, &val, buf)) { if ((val >= DIS_NEVER) && (val <= DIS_ALWAYS)) @@ -1862,17 +2017,12 @@ wd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs, if (check_setup_args("debug", &flags, &val, buf)) hostdata->args = val & DB_MASK; - if (check_setup_args("clock", &flags, &val, buf)) { - if (val > 7 && val < 11) - val = WD33C93_FS_8_10; - else if (val > 11 && val < 16) - val = WD33C93_FS_12_15; - else if (val > 15 && val < 21) - val = WD33C93_FS_16_20; - else - val = WD33C93_FS_8_10; - hostdata->clock_freq = val; - } + if (check_setup_args("burst", &flags, &val, buf)) + hostdata->dma_mode = val ? CTRL_BURST:CTRL_DMA; + + if (WD33C93_FS_16_20 == hostdata->clock_freq /* divisor 4 */ + && check_setup_args("fast", &flags, &val, buf)) + hostdata->fast = !!val; if ((i = check_setup_args("next", &flags, &val, buf))) { while (i) @@ -1917,53 +2067,65 @@ wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off char tbuf[128]; struct WD33C93_hostdata *hd; struct scsi_cmnd *cmd; - int x, i; + int x; static int stop = 0; hd = (struct WD33C93_hostdata *) instance->hostdata; /* If 'in' is TRUE we need to _read_ the proc file. We accept the following - * keywords (same format as command-line, but only ONE per read): + * keywords (same format as command-line, but arguments are not optional): * debug * disconnect * period * resync * proc * nodma + * level2 + * burst + * fast + * nosync */ if (in) { buf[len] = '\0'; - bp = buf; + for (bp = buf; *bp; ) { + while (',' == *bp || ' ' == *bp) + ++bp; if (!strncmp(bp, "debug:", 6)) { - bp += 6; - hd->args = simple_strtoul(bp, NULL, 0) & DB_MASK; + hd->args = simple_strtoul(bp+6, &bp, 0) & DB_MASK; } else if (!strncmp(bp, "disconnect:", 11)) { - bp += 11; - x = simple_strtoul(bp, NULL, 0); + x = simple_strtoul(bp+11, &bp, 0); if (x < DIS_NEVER || x > DIS_ALWAYS) x = DIS_ADAPTIVE; hd->disconnect = x; } else if (!strncmp(bp, "period:", 7)) { - bp += 7; - x = simple_strtoul(bp, NULL, 0); + x = simple_strtoul(bp+7, &bp, 0); hd->default_sx_per = - sx_table[round_period((unsigned int) x)].period_ns; + hd->sx_table[round_period((unsigned int) x, + hd->sx_table)].period_ns; } else if (!strncmp(bp, "resync:", 7)) { - bp += 7; - x = simple_strtoul(bp, NULL, 0); - for (i = 0; i < 7; i++) - if (x & (1 << i)) - hd->sync_stat[i] = SS_UNSET; + set_resync(hd, (int)simple_strtoul(bp+7, &bp, 0)); } else if (!strncmp(bp, "proc:", 5)) { - bp += 5; - hd->proc = simple_strtoul(bp, NULL, 0); + hd->proc = simple_strtoul(bp+5, &bp, 0); } else if (!strncmp(bp, "nodma:", 6)) { - bp += 6; - hd->no_dma = simple_strtoul(bp, NULL, 0); + hd->no_dma = simple_strtoul(bp+6, &bp, 0); } else if (!strncmp(bp, "level2:", 7)) { - bp += 7; - hd->level2 = simple_strtoul(bp, NULL, 0); + hd->level2 = simple_strtoul(bp+7, &bp, 0); + } else if (!strncmp(bp, "burst:", 6)) { + hd->dma_mode = + simple_strtol(bp+6, &bp, 0) ? CTRL_BURST:CTRL_DMA; + } else if (!strncmp(bp, "fast:", 5)) { + x = !!simple_strtol(bp+5, &bp, 0); + if (x != hd->fast) + set_resync(hd, 0xff); + hd->fast = x; + } else if (!strncmp(bp, "nosync:", 7)) { + x = simple_strtoul(bp+7, &bp, 0); + set_resync(hd, x ^ hd->no_sync); + hd->no_sync = x; + } else { + break; /* unknown keyword,syntax-error,... */ + } } return len; } @@ -1977,8 +2139,9 @@ wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off strcat(bp, tbuf); } if (hd->proc & PR_INFO) { - sprintf(tbuf, "\nclock_freq=%02x no_sync=%02x no_dma=%d", - hd->clock_freq, hd->no_sync, hd->no_dma); + sprintf(tbuf, "\nclock_freq=%02x no_sync=%02x no_dma=%d" + " dma_mode=%02x fast=%d", + hd->clock_freq, hd->no_sync, hd->no_dma, hd->dma_mode, hd->fast); strcat(bp, tbuf); strcat(bp, "\nsync_xfer[] = "); for (x = 0; x < 7; x++) { diff --git a/drivers/scsi/wd33c93.h b/drivers/scsi/wd33c93.h index edcb0365cf0c..61ffb860dacc 100644 --- a/drivers/scsi/wd33c93.h +++ b/drivers/scsi/wd33c93.h @@ -155,6 +155,9 @@ #define WD33C93_FS_12_15 OWNID_FS_12 #define WD33C93_FS_16_20 OWNID_FS_16 + /* pass input-clock explicitely. accepted mhz values are 8-10,12-20 */ +#define WD33C93_FS_MHZ(mhz) (mhz) + /* Control register */ #define CTRL_HSP 0x01 #define CTRL_HA 0x02 @@ -253,6 +256,9 @@ struct WD33C93_hostdata { uchar sync_stat[8]; /* status of sync negotiation per target */ uchar no_sync; /* bitmask: don't do sync on these targets */ uchar no_dma; /* set this flag to disable DMA */ + uchar dma_mode; /* DMA Burst Mode or Single Byte DMA */ + uchar fast; /* set this flag to enable Fast SCSI */ + struct sx_period sx_table[9]; /* transfer periods for actual DTC-setting */ #ifdef PROC_INTERFACE uchar proc; /* bitmask: what's in proc output */ #ifdef PROC_STATISTICS -- cgit v1.2.2 From 8f3334edae93f8b664417f4140d4d9dc9a003fe4 Mon Sep 17 00:00:00 2001 From: peter fuerst Date: Mon, 12 Feb 2007 15:27:17 +0100 Subject: [SCSI] sgiwd93: interfacing to wd33c93 1) sgiwd93 used to switch off asynchronous mode on the wd33c93, discarding any "nosync"-requests from the commandline. But we need to allow "nosync"-requests for selected devices, for example the Pioneer DVD305S. (For the curious: this device accepts the SDTR from wd33c93 and success- fully sends inquiry data in sync mode, but after the data phase in the inquiry command does an unexpected disconnect, seemingly sending no "status" or "command complete". Forcing async transfers makes it work together flawlessly with the wd33c93. Of course, preferable would be, to implement wd33c93's "resume command" stuff, but that probably will not come soon.) 2) Maximize benefit from the preceding Fast SCSI patch for wd33c93 by passing the higher input-clock frequency explicitely. To be applied after the mentioned wd33c93 patch. Signed-off-by: peter fuerst Signed-off-by: James Bottomley --- drivers/scsi/sgiwd93.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c index e81f97a35bc8..a15752b37990 100644 --- a/drivers/scsi/sgiwd93.c +++ b/drivers/scsi/sgiwd93.c @@ -244,9 +244,10 @@ static struct Scsi_Host * __init sgiwd93_setup_scsi( regs.SASR = wdregs + 3; regs.SCMD = wdregs + 7; - wd33c93_init(host, regs, dma_setup, dma_stop, WD33C93_FS_16_20); + wd33c93_init(host, regs, dma_setup, dma_stop, WD33C93_FS_MHZ(20)); - hdata->wh.no_sync = 0; + if (hdata->wh.no_sync == 0xff) + hdata->wh.no_sync = 0; if (request_irq(irq, sgiwd93_intr, 0, "SGI WD93", (void *) host)) { printk(KERN_WARNING "sgiwd93: Could not register irq %d " -- cgit v1.2.2 From 930e99bd1320d78c7d8866595e81b8fc7dc8739b Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Tue, 13 Feb 2007 23:21:52 +0900 Subject: [SCSI] tgt: fix the user/kernel ring buffer interface This patches fixes two bugs in the scsi target infrastructure's user/kernel interface. - It wrongly assumes that the ring buffer size of the interface (64KB) is larger than or equal to the system page size. This patch sets the ring buffer size to PAGE_SIZE if the system page size is larger. - It uses PAGE_SIZE in the header file exported to userspace. This patch removes it. Signed-off-by: FUJITA Tomonori Signed-off-by: James Bottomley --- drivers/scsi/scsi_tgt_if.c | 8 ++++++++ include/scsi/scsi_tgt_if.h | 3 --- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/scsi_tgt_if.c b/drivers/scsi/scsi_tgt_if.c index f2344ab8deff..0e08817fdecf 100644 --- a/drivers/scsi/scsi_tgt_if.c +++ b/drivers/scsi/scsi_tgt_if.c @@ -33,6 +33,14 @@ #include "scsi_tgt_priv.h" +#if TGT_RING_SIZE < PAGE_SIZE +# define TGT_RING_SIZE PAGE_SIZE +#endif + +#define TGT_RING_PAGES (TGT_RING_SIZE >> PAGE_SHIFT) +#define TGT_EVENT_PER_PAGE (PAGE_SIZE / sizeof(struct tgt_event)) +#define TGT_MAX_EVENTS (TGT_EVENT_PER_PAGE * TGT_RING_PAGES) + struct tgt_ring { u32 tr_idx; unsigned long tr_pages[TGT_RING_PAGES]; diff --git a/include/scsi/scsi_tgt_if.h b/include/scsi/scsi_tgt_if.h index 46d5e70d7215..07d6e77ae895 100644 --- a/include/scsi/scsi_tgt_if.h +++ b/include/scsi/scsi_tgt_if.h @@ -83,8 +83,5 @@ struct tgt_event { } __attribute__ ((aligned (sizeof(uint64_t)))); #define TGT_RING_SIZE (1UL << 16) -#define TGT_RING_PAGES (TGT_RING_SIZE >> PAGE_SHIFT) -#define TGT_EVENT_PER_PAGE (PAGE_SIZE / sizeof(struct tgt_event)) -#define TGT_MAX_EVENTS (TGT_EVENT_PER_PAGE * TGT_RING_PAGES) #endif -- cgit v1.2.2 From 4520b0089b41151ab3cc3ae1ee92d0aa19d88aae Mon Sep 17 00:00:00 2001 From: Richard Knutsson Date: Wed, 14 Feb 2007 01:40:39 +0100 Subject: [SCSI] megaraid: pci_module_init to pci_register_driver Convert pci_module_init() to pci_register_driver(). Signed-off-by: Richard Knutsson Acked-by: "Patro, Sumant" Signed-off-by: James Bottomley --- drivers/scsi/megaraid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 808a1b8c4043..0aa3304f6b9b 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -5072,7 +5072,7 @@ static int __init megaraid_init(void) "megaraid: failed to create megaraid root\n"); } #endif - error = pci_module_init(&megaraid_pci_driver); + error = pci_register_driver(&megaraid_pci_driver); if (error) { #ifdef CONFIG_PROC_FS remove_proc_entry("megaraid", &proc_root); -- cgit v1.2.2 From 8d63f375051bfb1506fa546db840af8510d1cd60 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Wed, 14 Feb 2007 14:28:36 -0600 Subject: [SCSI] lpfc: add PCI error recovery support This patch adds PCI Error recovery support to the Emulex Lightpulse Fibrechannel (lpfc) SCSI device driver. Lightly tested at this point, works. Signed-off-by: Linas Vepstas Acked-by: Bino.Sebastian@Emulex.Com Acked-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_init.c | 97 +++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/lpfc/lpfc_sli.c | 12 ++++++ 2 files changed, 109 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index afca45cdbcef..9d014e5a81c4 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -518,6 +518,10 @@ lpfc_handle_eratt(struct lpfc_hba * phba) struct lpfc_sli *psli = &phba->sli; struct lpfc_sli_ring *pring; uint32_t event_data; + /* If the pci channel is offline, ignore possible errors, + * since we cannot communicate with the pci card anyway. */ + if (pci_channel_offline(phba->pcidev)) + return; if (phba->work_hs & HS_FFER6 || phba->work_hs & HS_FFER5) { @@ -1797,6 +1801,92 @@ lpfc_pci_remove_one(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); } +/** + * lpfc_io_error_detected - called when PCI error is detected + * @pdev: Pointer to PCI device + * @state: The current pci conneection state + * + * This function is called after a PCI bus error affecting + * this device has been detected. + */ +static pci_ers_result_t lpfc_io_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + struct Scsi_Host *host = pci_get_drvdata(pdev); + struct lpfc_hba *phba = (struct lpfc_hba *)host->hostdata; + struct lpfc_sli *psli = &phba->sli; + struct lpfc_sli_ring *pring; + + if (state == pci_channel_io_perm_failure) { + lpfc_pci_remove_one(pdev); + return PCI_ERS_RESULT_DISCONNECT; + } + pci_disable_device(pdev); + /* + * There may be I/Os dropped by the firmware. + * Error iocb (I/O) on txcmplq and let the SCSI layer + * retry it after re-establishing link. + */ + pring = &psli->ring[psli->fcp_ring]; + lpfc_sli_abort_iocb_ring(phba, pring); + + /* Request a slot reset. */ + return PCI_ERS_RESULT_NEED_RESET; +} + +/** + * lpfc_io_slot_reset - called after the pci bus has been reset. + * @pdev: Pointer to PCI device + * + * Restart the card from scratch, as if from a cold-boot. + */ +static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev) +{ + struct Scsi_Host *host = pci_get_drvdata(pdev); + struct lpfc_hba *phba = (struct lpfc_hba *)host->hostdata; + struct lpfc_sli *psli = &phba->sli; + int bars = pci_select_bars(pdev, IORESOURCE_MEM); + + dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n"); + if (pci_enable_device_bars(pdev, bars)) { + printk(KERN_ERR "lpfc: Cannot re-enable " + "PCI device after reset.\n"); + return PCI_ERS_RESULT_DISCONNECT; + } + + pci_set_master(pdev); + + /* Re-establishing Link */ + spin_lock_irq(phba->host->host_lock); + phba->fc_flag |= FC_ESTABLISH_LINK; + psli->sli_flag &= ~LPFC_SLI2_ACTIVE; + spin_unlock_irq(phba->host->host_lock); + + + /* Take device offline; this will perform cleanup */ + lpfc_offline(phba); + lpfc_sli_brdrestart(phba); + + return PCI_ERS_RESULT_RECOVERED; +} + +/** + * lpfc_io_resume - called when traffic can start flowing again. + * @pdev: Pointer to PCI device + * + * This callback is called when the error recovery driver tells us that + * its OK to resume normal operation. + */ +static void lpfc_io_resume(struct pci_dev *pdev) +{ + struct Scsi_Host *host = pci_get_drvdata(pdev); + struct lpfc_hba *phba = (struct lpfc_hba *)host->hostdata; + + if (lpfc_online(phba) == 0) { + mod_timer(&phba->fc_estabtmo, jiffies + HZ * 60); + } +} + static struct pci_device_id lpfc_id_table[] = { {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_VIPER, PCI_ANY_ID, PCI_ANY_ID, }, @@ -1857,11 +1947,18 @@ static struct pci_device_id lpfc_id_table[] = { MODULE_DEVICE_TABLE(pci, lpfc_id_table); +static struct pci_error_handlers lpfc_err_handler = { + .error_detected = lpfc_io_error_detected, + .slot_reset = lpfc_io_slot_reset, + .resume = lpfc_io_resume, +}; + static struct pci_driver lpfc_driver = { .name = LPFC_DRIVER_NAME, .id_table = lpfc_id_table, .probe = lpfc_pci_probe_one, .remove = __devexit_p(lpfc_pci_remove_one), + .err_handler = &lpfc_err_handler, }; static int __init diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index a4128e19338a..9fb6960a8ada 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -2104,6 +2104,10 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag) volatile uint32_t word0, ldata; void __iomem *to_slim; + /* If the PCI channel is in offline state, do not post mbox. */ + if (unlikely(pci_channel_offline(phba->pcidev))) + return MBX_NOT_FINISHED; + psli = &phba->sli; spin_lock_irqsave(phba->host->host_lock, drvr_flag); @@ -2407,6 +2411,10 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *nextiocb; IOCB_t *iocb; + /* If the PCI channel is in offline state, do not post iocbs. */ + if (unlikely(pci_channel_offline(phba->pcidev))) + return IOCB_ERROR; + /* * We should never get an IOCB if we are in a < LINK_DOWN state */ @@ -3154,6 +3162,10 @@ lpfc_intr_handler(int irq, void *dev_id) if (unlikely(!phba)) return IRQ_NONE; + /* If the pci channel is offline, ignore all the interrupts. */ + if (unlikely(pci_channel_offline(phba->pcidev))) + return IRQ_NONE; + phba->sli.slistat.sli_intr++; /* -- cgit v1.2.2 From a29fdd3c2a3e53b67baa5031372fd78fddaf48fa Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Thu, 15 Feb 2007 15:25:35 -0600 Subject: [SCSI] aic94xx: tie driver to the major number of the sequencer firmware The sequencer firmware file has both a string (currently showing V17/10c6) and a number (currently set to 1.1). It has become apparent that Adaptec may issue sequencer firmware in the future which could be incompatible with the current driver. Therefore, the driver will be tied to the particular major number of the firmware (i.e. the current driver will load any 1.x firmware). Additionally, the driver will print out both the ascii string and the major number, so with this pach the current firmware will print out aic94xx: Found sequencer firmware version 1.1 (V17/10c6) Signed-off-by: James Bottomley --- drivers/scsi/aic94xx/aic94xx_seq.c | 13 ++++++++++--- drivers/scsi/aic94xx/aic94xx_seq.h | 1 + 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/aic94xx/aic94xx_seq.c b/drivers/scsi/aic94xx/aic94xx_seq.c index eae7a247bece..c750fbf7013b 100644 --- a/drivers/scsi/aic94xx/aic94xx_seq.c +++ b/drivers/scsi/aic94xx/aic94xx_seq.c @@ -44,7 +44,6 @@ #define PAUSE_TRIES 1000 static const struct firmware *sequencer_fw; -static const char *sequencer_version; static u16 cseq_vecs[CSEQ_NUM_VECS], lseq_vecs[LSEQ_NUM_VECS], mode2_task, cseq_idle_loop, lseq_idle_loop; static u8 *cseq_code, *lseq_code; @@ -1276,7 +1275,6 @@ static int asd_request_firmware(struct asd_ha_struct *asd_ha) header.csum = le32_to_cpu(hdr_ptr->csum); header.major = le32_to_cpu(hdr_ptr->major); header.minor = le32_to_cpu(hdr_ptr->minor); - sequencer_version = hdr_ptr->version; header.cseq_table_offset = le32_to_cpu(hdr_ptr->cseq_table_offset); header.cseq_table_size = le32_to_cpu(hdr_ptr->cseq_table_size); header.lseq_table_offset = le32_to_cpu(hdr_ptr->lseq_table_offset); @@ -1303,6 +1301,16 @@ static int asd_request_firmware(struct asd_ha_struct *asd_ha) return -EINVAL; } + asd_printk("Found sequencer Firmware version %d.%d (%s)\n", + header.major, header.minor, hdr_ptr->version); + + if (header.major != SAS_RAZOR_SEQUENCER_FW_MAJOR) { + asd_printk("Firmware Major Version Mismatch;" + "driver requires version %d.X", + SAS_RAZOR_SEQUENCER_FW_MAJOR); + return -EINVAL; + } + ptr_cseq_vecs = (u16 *)&sequencer_fw->data[header.cseq_table_offset]; ptr_lseq_vecs = (u16 *)&sequencer_fw->data[header.lseq_table_offset]; mode2_task = header.mode2_task; @@ -1335,7 +1343,6 @@ int asd_init_seqs(struct asd_ha_struct *asd_ha) return err; } - asd_printk("using sequencer %s\n", sequencer_version); err = asd_seq_download_seqs(asd_ha); if (err) { asd_printk("couldn't download sequencers for %s\n", diff --git a/drivers/scsi/aic94xx/aic94xx_seq.h b/drivers/scsi/aic94xx/aic94xx_seq.h index 9437ff0ae3a4..2ea6a0d52208 100644 --- a/drivers/scsi/aic94xx/aic94xx_seq.h +++ b/drivers/scsi/aic94xx/aic94xx_seq.h @@ -31,6 +31,7 @@ #define LSEQ_NUM_VECS 11 #define SAS_RAZOR_SEQUENCER_FW_FILE "aic94xx-seq.fw" +#define SAS_RAZOR_SEQUENCER_FW_MAJOR 1 /* Note: All quantites in the sequencer file are little endian */ struct sequencer_file_header { -- cgit v1.2.2 From e423ee31db92d4e298c137814a4341e1cd05739e Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 16 Feb 2007 01:46:38 -0800 Subject: [SCSI] scsi_scan.c: handle bad inquiry responses A particular USB device has been reporting short inquiry lengths. The SCSI code cannot operate properly unless we get an inquiry length of 36 or above (because of the way we parse vendor and product), so assume at least 36 bytes are valid even if the device reports fewer. This is wrong, but it's no worse than what we're doing now (using the garbage beyond the last reported valid byte). Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/scsi_scan.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index a43b9ec3aefd..7757e558d523 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -654,6 +654,19 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result, * short INQUIRY), an abort here prevents any further use of the * device, including spin up. * + * On the whole, the best approach seems to be to assume the first + * 36 bytes are valid no matter what the device says. That's + * better than copying < 36 bytes to the inquiry-result buffer + * and displaying garbage for the Vendor, Product, or Revision + * strings. + */ + if (sdev->inquiry_len < 36) { + printk(KERN_INFO "scsi scan: INQUIRY result too short (%d)," + " using 36\n", sdev->inquiry_len); + sdev->inquiry_len = 36; + } + + /* * Related to the above issue: * * XXX Devices (disk or all?) should be sent a TEST UNIT READY, -- cgit v1.2.2 From e790b3dd2b59e2418923fa0122d53e57ffa5a868 Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Fri, 16 Feb 2007 01:46:24 -0800 Subject: [SCSI] aic79xx: remove extra newline from info message This extra newline character introduces a completely empty line in dmesg as the calling function itself adds a newline. Signed-off-by: Rolf Eike Beer Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic79xx_osm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index c7fe478f4813..2be03e975d97 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -418,7 +418,6 @@ ahd_linux_info(struct Scsi_Host *host) strcat(bp, " "); ahd_controller_info(ahd, ahd_info); strcat(bp, ahd_info); - strcat(bp, "\n"); return (bp); } -- cgit v1.2.2 From a9b7320294f885be6087bdef7a0e25922c36eb1b Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Fri, 16 Feb 2007 01:46:25 -0800 Subject: [SCSI] scsi_transport.h should include scsi_device.h scsi_transport.h defines the inline function scsi_transport_device_data() that dereferences a pointer of "struct scsi_device *". Since the struct is not known by the header this might break compilation. Include scsi/scsi_device.h to not rely on users doing the correct magic include order. Signed-off-by: Rolf Eike Beer Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- include/scsi/scsi_transport.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/scsi/scsi_transport.h b/include/scsi/scsi_transport.h index cca1d4926d2a..3c18baa65a72 100644 --- a/include/scsi/scsi_transport.h +++ b/include/scsi/scsi_transport.h @@ -22,6 +22,7 @@ #include #include +#include struct scsi_transport_template { /* the attribute containers */ -- cgit v1.2.2 From af37acfb63d8e924550e67b884dbd1c478e26c96 Mon Sep 17 00:00:00 2001 From: Sumant Patro Date: Wed, 14 Feb 2007 12:34:46 -0800 Subject: [SCSI] megaraid_sas: do not process cmds if hw_crit_error is set Checks if hw_crit_error is set. If it is set, we donot process commands. Checks added in megasas_queue_command and command completion routines. Signed-off-by: Sumant Patro Signed-off-by: James Bottomley --- drivers/scsi/megaraid/megaraid_sas.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index 15e24fcc84f3..6ff540140807 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c @@ -841,6 +841,11 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *)) instance = (struct megasas_instance *) scmd->device->host->hostdata; + + /* Don't process if we have already declared adapter dead */ + if (instance->hw_crit_error) + return SCSI_MLQUEUE_HOST_BUSY; + scmd->scsi_done = done; scmd->result = 0; @@ -1282,11 +1287,13 @@ megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status) if(instance->instancet->clear_intr(instance->reg_set)) return IRQ_NONE; + if (instance->hw_crit_error) + goto out_done; /* * Schedule the tasklet for cmd completion */ tasklet_schedule(&instance->isr_tasklet); - +out_done: return IRQ_HANDLED; } @@ -1741,6 +1748,10 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr) struct megasas_cmd *cmd; struct megasas_instance *instance = (struct megasas_instance *)instance_addr; + /* If we have already declared adapter dead, donot complete cmds */ + if (instance->hw_crit_error) + return; + producer = *instance->producer; consumer = *instance->consumer; -- cgit v1.2.2 From cf62a0a543fbab15286509d2e04e3dcf5549e966 Mon Sep 17 00:00:00 2001 From: Sumant Patro Date: Wed, 14 Feb 2007 12:41:55 -0800 Subject: [SCSI] megaraid_sas: add bios_param in scsi_host_template Signed-off-by: Sumant Patro Signed-off-by: James Bottomley --- drivers/scsi/megaraid/megaraid_sas.c | 45 ++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index 6ff540140807..9c5e4da5a132 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -1014,6 +1015,49 @@ static int megasas_reset_bus_host(struct scsi_cmnd *scmd) return ret; } +/** + * megasas_bios_param - Returns disk geometry for a disk + * @sdev: device handle + * @bdev: block device + * @capacity: drive capacity + * @geom: geometry parameters + */ +static int +megasas_bios_param(struct scsi_device *sdev, struct block_device *bdev, + sector_t capacity, int geom[]) +{ + int heads; + int sectors; + sector_t cylinders; + unsigned long tmp; + /* Default heads (64) & sectors (32) */ + heads = 64; + sectors = 32; + + tmp = heads * sectors; + cylinders = capacity; + + sector_div(cylinders, tmp); + + /* + * Handle extended translation size for logical drives > 1Gb + */ + + if (capacity >= 0x200000) { + heads = 255; + sectors = 63; + tmp = heads*sectors; + cylinders = capacity; + sector_div(cylinders, tmp); + } + + geom[0] = heads; + geom[1] = sectors; + geom[2] = cylinders; + + return 0; +} + /** * megasas_service_aen - Processes an event notification * @instance: Adapter soft state @@ -1054,6 +1098,7 @@ static struct scsi_host_template megasas_template = { .eh_device_reset_handler = megasas_reset_device, .eh_bus_reset_handler = megasas_reset_bus_host, .eh_host_reset_handler = megasas_reset_bus_host, + .bios_param = megasas_bios_param, .use_clustering = ENABLE_CLUSTERING, }; -- cgit v1.2.2 From 9f35fa8a14e6216a859e2dfbe50ade497f9603ef Mon Sep 17 00:00:00 2001 From: Sumant Patro Date: Wed, 14 Feb 2007 12:55:45 -0800 Subject: [SCSI] megaraid_sas: replace pci_alloc_consitent with dma_alloc_coherent in ioctl path Replaced pci_alloc_consistent with dma_alloc_coherent from the ioctl path. This is to avoid situations where ioctl fails for lack of memory (when system under heavy stress). Signed-off-by: Sumant Patro Signed-off-by: James Bottomley --- drivers/scsi/megaraid/megaraid_sas.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index 9c5e4da5a132..4070894ed5f0 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c @@ -2711,9 +2711,9 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, * For each user buffer, create a mirror buffer and copy in */ for (i = 0; i < ioc->sge_count; i++) { - kbuff_arr[i] = pci_alloc_consistent(instance->pdev, + kbuff_arr[i] = dma_alloc_coherent(&instance->pdev->dev, ioc->sgl[i].iov_len, - &buf_handle); + &buf_handle, GFP_KERNEL); if (!kbuff_arr[i]) { printk(KERN_DEBUG "megasas: Failed to alloc " "kernel SGL buffer for IOCTL \n"); @@ -2740,8 +2740,8 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, } if (ioc->sense_len) { - sense = pci_alloc_consistent(instance->pdev, ioc->sense_len, - &sense_handle); + sense = dma_alloc_coherent(&instance->pdev->dev, ioc->sense_len, + &sense_handle, GFP_KERNEL); if (!sense) { error = -ENOMEM; goto out; @@ -2800,12 +2800,12 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, out: if (sense) { - pci_free_consistent(instance->pdev, ioc->sense_len, + dma_free_coherent(&instance->pdev->dev, ioc->sense_len, sense, sense_handle); } for (i = 0; i < ioc->sge_count && kbuff_arr[i]; i++) { - pci_free_consistent(instance->pdev, + dma_free_coherent(&instance->pdev->dev, kern_sge32[i].length, kbuff_arr[i], kern_sge32[i].phys_addr); } -- cgit v1.2.2 From 02b01e010afeeb49328d35650d70721d2ca3fd59 Mon Sep 17 00:00:00 2001 From: Sumant Patro Date: Wed, 14 Feb 2007 13:00:55 -0800 Subject: [SCSI] megaraid_sas: return sync cache call with success FW does not support SYNCHRONIZE_CACHE cmd. FW flush cache on its own. So, we just return success from the megasas_queue_command. Signed-off-by: Sumant Patro Signed-off-by: James Bottomley --- drivers/scsi/megaraid/megaraid_sas.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index 4070894ed5f0..01eb9b5870b5 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c @@ -856,6 +856,18 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *)) goto out_done; } + switch (scmd->cmnd[0]) { + case SYNCHRONIZE_CACHE: + /* + * FW takes care of flush cache on its own + * No need to send it down + */ + scmd->result = DID_OK << 16; + goto out_done; + default: + break; + } + cmd = megasas_get_cmd(instance); if (!cmd) return SCSI_MLQUEUE_HOST_BUSY; -- cgit v1.2.2 From cc5968c83edc8c797177db3adf95beafa2b7f365 Mon Sep 17 00:00:00 2001 From: Sumant Patro Date: Wed, 14 Feb 2007 13:05:42 -0800 Subject: [SCSI] megaraid_sas: update version and author info Signed-off-by: Sumant Patro Signed-off-by: James Bottomley --- drivers/scsi/megaraid/megaraid_sas.c | 8 +++++--- drivers/scsi/megaraid/megaraid_sas.h | 6 +++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index 01eb9b5870b5..7a812677ff8a 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c @@ -10,11 +10,13 @@ * 2 of the License, or (at your option) any later version. * * FILE : megaraid_sas.c - * Version : v00.00.03.05 + * Version : v00.00.03.10-rc1 * * Authors: - * Sreenivas Bagalkote - * Sumant Patro + * (email-id : megaraidlinux@lsi.com) + * Sreenivas Bagalkote + * Sumant Patro + * Bo Yang * * List of supported controllers * diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index cacb3ad92527..e862992ee377 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -18,9 +18,9 @@ /* * MegaRAID SAS Driver meta data */ -#define MEGASAS_VERSION "00.00.03.05" -#define MEGASAS_RELDATE "Oct 02, 2006" -#define MEGASAS_EXT_VERSION "Mon Oct 02 11:21:32 PDT 2006" +#define MEGASAS_VERSION "00.00.03.10-rc1" +#define MEGASAS_RELDATE "Feb 14, 2007" +#define MEGASAS_EXT_VERSION "Wed Feb 14 10:14:25 PST 2007" /* * Device IDs -- cgit v1.2.2 From 74feb53e8b5020e790e12c6331cbe885d276cc60 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 8 Jan 2007 11:07:41 -0500 Subject: [SCSI] scsi_proc.c: display sdev->scsi_level correctly This patch (as833) fixes the "SCSI revision" output for /proc/scsi/scsi. If the scsi_level value is 0 (UNKNOWN), we want it to show up as "0", not "ffffffff". Signed-off-by: Alan Stern Signed-off-by: James Bottomley --- drivers/scsi/scsi_proc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index 69d6e9b198c4..bb6f051beda8 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c @@ -179,9 +179,8 @@ static int proc_print_scsidevice(struct device *dev, void *data) seq_printf(s, "\n"); seq_printf(s, " Type: %s ", scsi_device_type(sdev->type)); - seq_printf(s, " ANSI" - " SCSI revision: %02x", (sdev->scsi_level - 1) ? - sdev->scsi_level - 1 : 1); + seq_printf(s, " ANSI SCSI revision: %02x", + sdev->scsi_level - (sdev->scsi_level > 1)); if (sdev->scsi_level == 2) seq_printf(s, " CCS\n"); else -- cgit v1.2.2 From 7c9d6f16f50d3aeb780e4f103a1ba8b35d9ae803 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 8 Jan 2007 11:12:32 -0500 Subject: [SCSI] SCSI core: better initialization for sdev->scsi_level This patch will affect the CDB in INQUIRY commands sent to LUNs above 0 when LUN-0 reports a scsi_level of 0; the LUN bits will no longer be set in the second byte of the CDB. This is as it should be. Nevertheless, it's possible that some wacky device might be adversely affected. I doubt anyone will complain... Signed-off-by: Alan Stern Signed-off-by: James Bottomley --- drivers/scsi/scsi_scan.c | 1 + drivers/scsi/scsi_sysfs.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 7757e558d523..6905ffd135b3 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -385,6 +385,7 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, INIT_LIST_HEAD(&starget->siblings); INIT_LIST_HEAD(&starget->devices); starget->state = STARGET_RUNNING; + starget->scsi_level = SCSI_2; retry: spin_lock_irqsave(shost->host_lock, flags); diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 259c90cfa367..c275dcac3f18 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -922,7 +922,7 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev) snprintf(sdev->sdev_classdev.class_id, BUS_ID_SIZE, "%d:%d:%d:%d", sdev->host->host_no, sdev->channel, sdev->id, sdev->lun); - sdev->scsi_level = SCSI_2; + sdev->scsi_level = starget->scsi_level; transport_setup_device(&sdev->sdev_gendev); spin_lock_irqsave(shost->host_lock, flags); list_add_tail(&sdev->same_target_siblings, &starget->devices); -- cgit v1.2.2