mptsas hangs caused by ATA pass-through explained
Subsystems (2)
I may have an explanation for the LSI 1068 HBA hangs provoked by ATA pass-through commands, in particular by smartctl.
First, my version of the symptoms. On an LSI SAS1068E B3 HBA running 01.29.00.00 firmware, with SATA disks, and with smartd running, I'm seeing occasional task, bus, and host resets, some of which lead to hard faults of the HBA requiring a reboot. Abusively looping the smartctl command,
# while true; do smartctl -a /dev/sdb > /dev/null; done
dramatically increases the frequency of these failures to nearly one per minute. A high IO load through the HBA while looping smartctl seems to improve the chance of a full scsi host reset or a non-recoverable hang.
I reduced what smartctl was doing down to a simple test case which causes the hang with a single IO when pointed at the sd interface. See the code at the bottom of this e-mail. It uses an SG_IO ioctl to issue a single pass-through ATA identify device command. If the buffer userspace gives for the read data has certain alignments, the task is issued to the HBA but the HBA fails to respond. If run against the sg interface, neither the test code nor smartctl causes a hang.
sd and sg handle the SG_IO ioctl slightly differently. Unless you specifically set a flag to do direct IO, sg passes a buffer of its own, which is page-aligned, to the block layer and later copies the result into the userspace buffer regardless of its alignment. sd, on the other hand, always does direct IO unless the userspace buffer fails an alignment test at block/blk-map.c line 57, in which case a page-aligned buffer is created and used for the transfer.
The alignment test currently checks for word-alignment, the default setup by scsi_lib.c; therefore, userspace buffers of almost any alignment are given directly to the HBA as DMA targets. The LSI 1068 hardware doesn't seem to like at least a couple of the alignments which cross a page boundary (see the test code below). Curiously, many page-boundary-crossing alignments do work just fine.
So, either the hardware has an bug handling certain alignments or the hardware has a stricter alignment requirement than the driver is advertising. If stricter alignment is required, then in no case should misaligned buffers from userspace be allowed through without being bounced or at least causing an error to be returned.
It seems the mptsas driver could use blk_queue_dma_alignment() to advertise a stricter alignment requirement. If it does, sd does the right thing and bounces misaligned buffers (see block/blk-map.c line 57). The following patch to 2.6.34-rc5 makes my symptoms go away. I'm sure this is the wrong place for this code, but it gets my idea across.
drivers/message/fusion/mptscsih.c +2 -0
@@ -2450,6 +2450,8 @@ mptscsih_slave_configure(struct scsi_device *sdev) ioc->name,sdev->tagged_supported, sdev->simple_tags, sdev->ordered_tags)); +blk_queue_dma_alignment (sdev->request_queue,512 -1 ); +return 0 ; }
I look forward to hearing from you guys who know this hardware and code better than I do. Is the hardware at fault, or should the driver be shielding the hardware better? Where's the right place to add this code, if it's the right fix?
Does this `fix' the problem for anyone besides me?
Regards,
-- Ryan Kuester
Here is a minimal bit of test code which causes the error. BEWARE: this will hose the HBA at which you point it. If that's controlling your root disk, you may hang your machine.
/*
* sg_bomb -- send SG_IO ioctl which causes LSI 1068 HBA to hang *
* usage: sg_bomb <device>
* e.g.: sg_bomb /dev/sdb
* e.g.: sg_bomb /dev/sg1
*
* Modify offset_into_page to adjust the degree of buffer misalignment.
*/
#include <unistd.h>
#include <scsi/sg.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
char* filename = argv[1];
unsigned int offset_into_page = 0xe40;
// works: unsigned int offset_into_page = 0x0;
// hangs: unsigned int offset_into_page = 0xf00;
// works: unsigned int offset_into_page = 0xf04;
unsigned char ata_identify_cmd[] = {0x85, 0x08, 0x0e, 0, 0, 0, 0x01,
0, 0, 0, 0, 0, 0, 0, 0xec, 0};
unsigned char sense[32];
unsigned char* data = valloc(0x2000) + offset_into_page;
struct sg_io_hdr hdr = {
.interface_id = 'S',
.dxfer_direction = SG_DXFER_FROM_DEV,
.cmdp = ata_identify_cmd,
.cmd_len = 16,
.dxferp = data,
.dxfer_len = 512,
.sbp = sense,
.mx_sb_len = sizeof(sense),
.timeout = 5000,
};
int fd;
if ((fd = open(filename, O_RDWR|O_NONBLOCK)) < 0)
perror();
return ioctl(fd, SG_IO, &hdr);
}Cláudio Martins
Tested-byQuoted 54 lines · On Mon, 26 Apr 2010 18:11:54 -0500 Ryan Kuester <[email protected]> wrote:
I may have an explanation for the LSI 1068 HBA hangs provoked by ATA pass-through commands, in particular by smartctl.
First, my version of the symptoms. On an LSI SAS1068E B3 HBA running 01.29.00.00 firmware, with SATA disks, and with smartd running, I'm seeing occasional task, bus, and host resets, some of which lead to hard faults of the HBA requiring a reboot. Abusively looping the smartctl command,
# while true; do smartctl -a /dev/sdb > /dev/null; donedramatically increases the frequency of these failures to nearly one per minute. A high IO load through the HBA while looping smartctl seems to improve the chance of a full scsi host reset or a non-recoverable hang.
I reduced what smartctl was doing down to a simple test case which causes the hang with a single IO when pointed at the sd interface. See the code at the bottom of this e-mail. It uses an
SG_IOioctl to issue a single pass-through ATA identify device command. If the buffer userspace gives for the read data has certain alignments, the task is issued to the HBA but the HBA fails to respond. If run against the sg interface, neither the test code nor smartctl causes a hang.sd and sg handle the
SG_IOioctl slightly differently. Unless you specifically set a flag to do direct IO, sg passes a buffer of its own, which is page-aligned, to the block layer and later copies the result into the userspace buffer regardless of its alignment. sd, on the other hand, always does direct IO unless the userspace buffer fails an alignment test atblock/blk-map.cline 57, in which case a page-aligned buffer is created and used for the transfer.The alignment test currently checks for word-alignment, the default setup by
scsi_lib.c; therefore, userspace buffers of almost any alignment are given directly to the HBA as DMA targets. The LSI 1068 hardware doesn't seem to like at least a couple of the alignments which cross a page boundary (see the test code below). Curiously, many page-boundary-crossing alignments do work just fine.So, either the hardware has an bug handling certain alignments or the hardware has a stricter alignment requirement than the driver is advertising. If stricter alignment is required, then in no case should misaligned buffers from userspace be allowed through without being bounced or at least causing an error to be returned.
It seems the mptsas driver could use
blk_queue_dma_alignment()to advertise a stricter alignment requirement. If it does, sd does the right thing and bounces misaligned buffers (seeblock/blk-map.cline 57). The following patch to 2.6.34-rc5 makes my symptoms go away. I'm sure this is the wrong place for this code, but it gets my idea across.drivers/message/fusion/mptscsih.c +0
-0
drivers/message/fusion/mptscsih.c mptscsih_slave_configure(struct scsi_device *sdev) · line 2457
Quoted 8 lines
drivers/message/fusion/mptscsih.c +2
-0@@ -2450,6 +2450,8 @@ mptscsih_slave_configure(struct scsi_device *sdev) ioc->name,sdev->tagged_supported, sdev->simple_tags, sdev->ordered_tags)); +blk_queue_dma_alignment (sdev->request_queue,512 -1 ); +return 0 ; }
Hello,
I have tested v2.6.34 on a box with 16 SATA disks attached to a
LSISAS1068E (through a port expander), with and without this patch:
With vanilla 2.6.34 I can reliably reproduce controller timeouts both
with the example code provided by Ryan and with a simple loop like:
while : ; do for d in ls /sys/block/ | grep sd ; do smartctl -a /dev/$d ; done ; done
The result are controller timeouts with the following kind of kernel messages:
mptscsih: ioc0: attempting task abort! (sc=ffff8802be18dc00)
sd 4:0:2:0: [sdc] CDB: ATA command pass through(16): 85 08 0e 00 00 00 01 00 00 00 00 00 00 00 ec 00
mptbase: ioc0: LogInfo(0x31140000): Originator={PL}, Code={IO Executed}, SubCode(0x0000)
mptscsih: ioc0: task abort: SUCCESS (sc=ffff8802be18dc00)
mptbase: ioc0: LogInfo(0x31112000): Originator={PL}, Code={Reset}, SubCode(0x2000)
mptbase: ioc0: LogInfo(0x31120101): Originator={PL}, Code={Abort}, SubCode(0x0101)
mptscsih: ioc0: attempting task abort! (sc=ffff8802be18dc00)
sd 4:0:2:0: [sdc] CDB: Test Unit Ready: 00 00 00 00 00 00
mptbase: ioc0: LogInfo(0x31112000): Originator={PL}, Code={Reset}, SubCode(0x2000)
mptscsih: ioc0: task abort: SUCCESS (sc=ffff8802be18dc00)
mptscsih: ioc0: attempting target reset! (sc=ffff8802be18dc00)
sd 4:0:2:0: [sdc] CDB: ATA command pass through(16): 85 08 0e 00 00 00 01 00 00 00 00 00 00 00 ec 00
mptscsih: ioc0: target reset: SUCCESS (sc=ffff8802be18dc00)
mptbase: ioc0: LogInfo(0x31112000): Originator={PL}, Code={Reset}, SubCode(0x2000)
mptbase: ioc0: LogInfo(0x31120101): Originator={PL}, Code={Abort}, SubCode(0x0101)
mptscsih: ioc0: attempting task abort! (sc=ffff8802be18dc00)
sd 4:0:2:0: [sdc] CDB: Test Unit Ready: 00 00 00 00 00 00
mptbase: ioc0: LogInfo(0x31112000): Originator={PL}, Code={Reset}, SubCode(0x2000)
mptscsih: ioc0: task abort: SUCCESS (sc=ffff8802be18dc00)
mptscsih: ioc0: attempting bus reset! (sc=ffff8802be18dc00)
sd 4:0:2:0: [sdc] CDB: ATA command pass through(16): 85 08 0e 00 00 00 01 00 00 00 00 00 00 00 ec 00
mptscsih: ioc0: bus reset: SUCCESS (sc=ffff8802be18dc00)
mptbase: ioc0: LogInfo(0x31112000): Originator={PL}, Code={Reset}, SubCode(0x2000)
mptbase: ioc0: LogInfo(0x31120101): Originator={PL}, Code={Abort}, SubCode(0x0101)
mptbase: ioc0: LogInfo(0x31120101): Originator={PL}, Code={Abort}, SubCode(0x0101)
mptscsih: ioc0: attempting host reset! (sc=ffff8802be18dc00)
mptscsih: ioc0: host reset: SUCCESS (sc=ffff8802be18dc00)
As described in
https://bugzilla.kernel.org/show_bug.cgi?id=13594
this can result in nasty side effects, like multiple drives getting
kicked out of an MD array.
With Ryan's patch applied on top of v2.6.34 I cannot reproduce the
above problem with my simple script nor with Ryan's example.
So, IMHO, this patch should be strongly considered for inclusion, or
else the root cause investigated further.
So, as far as I can tell:
I'm also glad to test any further patches, if it turns out that the
above is not the most correct fix for the issue.
Thanks in advance.
Best regards
Cláudio
Quoted 53 lines
I look forward to hearing from you guys who know this hardware and code better than I do. Is the hardware at fault, or should the driver be shielding the hardware better? Where's the right place to add this code, if it's the right fix?
Does this `fix' the problem for anyone besides me?
Regards,
-- Ryan KuesterHere is a minimal bit of test code which causes the error. BEWARE: this will hose the HBA at which you point it. If that's controlling your root disk, you may hang your machine.
/*
*sg_bomb-- sendSG_IOioctl which causes LSI 1068 HBA to hang *
* usage:sg_bomb<device>
* e.g.:sg_bomb/dev/sdb
* e.g.:sg_bomb/dev/sg1
*
* Modifyoffset_into_pageto adjust the degree of buffer misalignment.
*/#include <
unistd.h>
#include <scsi/sg.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <stdlib.h>int
main(int argc, char* argv[]){ char* filename = argv[1]; unsigned int offset_into_page = 0xe40; // works: unsigned int offset_into_page = 0x0; // hangs: unsigned int offset_into_page = 0xf00; // works: unsigned int offset_into_page = 0xf04; unsigned char ata_identify_cmd[] = {0x85, 0x08, 0x0e, 0, 0, 0, 0x01, 0, 0, 0, 0, 0, 0, 0, 0xec, 0}; unsigned char sense[32]; unsigned char* data = valloc(0x2000) + offset_into_page; struct sg_io_hdr hdr = { .interface_id = 'S', .dxfer_direction = SG_DXFER_FROM_DEV, .cmdp = ata_identify_cmd, .cmd_len = 16, .dxferp = data, .dxfer_len = 512, .sbp = sense, .mx_sb_len = sizeof(sense), .timeout = 5000,
Quoted 8 lines
};
int fd;
if ((fd = open(filename, O_RDWR|O_NONBLOCK)) < 0)
perror();
return ioctl(fd, SG_IO, &hdr);
}--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 86 lines
-----Original Message-----
From: Cláudio Martins [mailto:[email protected]]
Sent: Wednesday, June 02, 2010 1:14 AM
To: Ryan Kuester
Cc: Moore, Eric; Desai, Kashyap; DL-MPT Fusion Linux; Support, Software; [email protected]; [email protected]
Subject: Re: mptsas hangs caused by ATA pass-through explainedQuoted 5 lines · On Mon, 26 Apr 2010 18:11:54 -0500 Ryan Kuester <[email protected]> wrote:
I may have an explanation for the LSI 1068 HBA hangs provoked by ATA pass-through commands, in particular by smartctl.
First, my version of the symptoms. On an LSI SAS1068E B3 HBA running 01.29.00.00 firmware, with SATA disks, and with smartd running, I'm
seeing
Quoted 1 line
occasional task, bus, and host resets, some of which lead to hard
faults of
Quoted 5 lines
the HBA requiring a reboot. Abusively looping the smartctl command,
# while true; do smartctl -a /dev/sdb > /dev/null; donedramatically increases the frequency of these failures to nearly one
per
Quoted 1 line
minute. A high IO load through the HBA while looping smartctl seems
to
Quoted 1 line
improve the chance of a full scsi host reset or a non-recoverable
hang.
Quoted 3 lines
I reduced what smartctl was doing down to a simple test case which causes the hang with a single IO when pointed at the sd interface.
See
Quoted 1 line
the code at the bottom of this e-mail. It uses an
SG_IOioctl toissue
Quoted 3 lines
a single pass-through ATA identify device command. If the buffer userspace gives for the read data has certain alignments, the task is issued to the HBA but the HBA fails to respond. If run against the
sg
Quoted 4 lines
interface, neither the test code nor smartctl causes a hang.
sd and sg handle the
SG_IOioctl slightly differently. Unless you specifically set a flag to do direct IO, sg passes a buffer of itsown,
Quoted 2 lines
which is page-aligned, to the block layer and later copies the result into the userspace buffer regardless of its alignment. sd, on the
other
Quoted 2 lines
hand, always does direct IO unless the userspace buffer fails an alignment test at
block/blk-map.cline 57, in which case a page-aligned
Quoted 6 lines
buffer is created and used for the transfer.
The alignment test currently checks for word-alignment, the default setup by
scsi_lib.c; therefore, userspace buffers of almost any alignment are given directly to the HBA as DMA targets. The LSI 1068 hardware doesn't seem to like at least a couple of the alignmentswhich
Quoted 6 lines
cross a page boundary (see the test code below). Curiously, many page-boundary-crossing alignments do work just fine.
So, either the hardware has an bug handling certain alignments or the hardware has a stricter alignment requirement than the driver is advertising. If stricter alignment is required, then in no case
should
Quoted 4 lines
misaligned buffers from userspace be allowed through without being bounced or at least causing an error to be returned.
It seems the mptsas driver could use
blk_queue_dma_alignment()toadvertise
Quoted 1 line
a stricter alignment requirement. If it does, sd does the right
thing and
Quoted 1 line
bounces misaligned buffers (see
block/blk-map.cline 57). Thefollowing
Quoted 1 line
patch to 2.6.34-rc5 makes my symptoms go away. I'm sure this is the
wrong
Review
Quoted 3 lines
place for this code, but it gets my idea across.
(quoted diff) +0
-0
b/drivers/message/fusion/mptscsih.cdrivers/message/fusion/mptscsih.c mptscsih_slave_configure(struct scsi_device
Quoted 4 lines
index 6796597..1e034ad 100644
drivers/message/fusion/mptscsih.c +0
-0@@ -2450,6 +2450,8 @@ mptscsih_slave_configure(struct scsi_device*sdev)
Quoted 8 lines
drivers/message/fusion/mptscsih.c mptscsih_slave_configure(struct scsi_device *sdev) · line 2457
Quoted 8 lines
drivers/message/fusion/mptscsih.c +2
-0ioc->name,sdev->tagged_supported, sdev->simple_tags, sdev->ordered_tags)); +blk_queue_dma_alignment (sdev->request_queue,512 -1 ); +return 0 ; }
I have also verified this patch + also done code review with our developers including Eric Moore. Please consider this patch as an ACKed patch and schedule it for next upstream release.
Thanks,
Kashyap
Quoted 150 lines
Hello,
I have tested v2.6.34 on a box with 16 SATA disks attached to a
LSISAS1068E (through a port expander), with and without this patch:With vanilla 2.6.34 I can reliably reproduce controller timeouts both
with the example code provided by Ryan and with a simple loop like:while : ; do for d in
ls /sys/block/ | grep sd; do smartctl -a/dev/$d; done ; doneThe result are controller timeouts with the following kind of kernel
messages:mptscsih: ioc0: attempting task abort! (sc=ffff8802be18dc00) sd 4:0:2:0: [sdc] CDB: ATA command pass through(16): 85 08 0e 00 00 00 01 00 00 00 00 00 00 00 ec 00
mptbase: ioc0: LogInfo(0x31140000): Originator={PL}, Code={IO Executed}, SubCode(0x0000)
mptscsih: ioc0: task abort: SUCCESS (sc=ffff8802be18dc00)
mptbase: ioc0: LogInfo(0x31112000): Originator={PL}, Code={Reset}, SubCode(0x2000)
mptbase: ioc0: LogInfo(0x31120101): Originator={PL}, Code={Abort}, SubCode(0x0101)
mptscsih: ioc0: attempting task abort! (sc=ffff8802be18dc00) sd 4:0:2:0: [sdc] CDB: Test Unit Ready: 00 00 00 00 00 00
mptbase: ioc0: LogInfo(0x31112000): Originator={PL}, Code={Reset}, SubCode(0x2000)
mptscsih: ioc0: task abort: SUCCESS (sc=ffff8802be18dc00)
mptscsih: ioc0: attempting target reset! (sc=ffff8802be18dc00) sd 4:0:2:0: [sdc] CDB: ATA command pass through(16): 85 08 0e 00 00 00 01 00 00 00 00 00 00 00 ec 00
mptscsih: ioc0: target reset: SUCCESS (sc=ffff8802be18dc00)
mptbase: ioc0: LogInfo(0x31112000): Originator={PL}, Code={Reset}, SubCode(0x2000)
mptbase: ioc0: LogInfo(0x31120101): Originator={PL}, Code={Abort}, SubCode(0x0101)
mptscsih: ioc0: attempting task abort! (sc=ffff8802be18dc00) sd 4:0:2:0: [sdc] CDB: Test Unit Ready: 00 00 00 00 00 00
mptbase: ioc0: LogInfo(0x31112000): Originator={PL}, Code={Reset}, SubCode(0x2000)
mptscsih: ioc0: task abort: SUCCESS (sc=ffff8802be18dc00)
mptscsih: ioc0: attempting bus reset! (sc=ffff8802be18dc00) sd 4:0:2:0: [sdc] CDB: ATA command pass through(16): 85 08 0e 00 00 00 01 00 00 00 00 00 00 00 ec 00
mptscsih: ioc0: bus reset: SUCCESS (sc=ffff8802be18dc00)
mptbase: ioc0: LogInfo(0x31112000): Originator={PL}, Code={Reset}, SubCode(0x2000)
mptbase: ioc0: LogInfo(0x31120101): Originator={PL}, Code={Abort}, SubCode(0x0101)
mptbase: ioc0: LogInfo(0x31120101): Originator={PL}, Code={Abort}, SubCode(0x0101)
mptscsih: ioc0: attempting host reset! (sc=ffff8802be18dc00)
mptscsih: ioc0: host reset: SUCCESS (sc=ffff8802be18dc00)As described in
https://bugzilla.kernel.org/show_bug.cgi?id=13594
this can result in nasty side effects, like multiple drives getting
kicked out of an MD array.With Ryan's patch applied on top of v2.6.34 I cannot reproduce the
above problem with my simple script nor with Ryan's example.So, IMHO, this patch should be strongly considered for inclusion, or
else the root cause investigated further.So, as far as I can tell:
Tested-by Cláudio Martins <[email protected]>I'm also glad to test any further patches, if it turns out that the
above is not the most correct fix for the issue.Thanks in advance.
Best regards
Cláudio
Quoted 1 line
I look forward to hearing from you guys who know this hardware and
code
Quoted 2 lines
better than I do. Is the hardware at fault, or should the driver be shielding the hardware better? Where's the right place to add this
code, if
Quoted 9 lines
it's the right fix?
Does this `fix' the problem for anyone besides me?
Regards,
-- Ryan KuesterHere is a minimal bit of test code which causes the error. BEWARE:
this
Quoted 11 lines
will hose the HBA at which you point it. If that's controlling your root disk, you may hang your machine.
/*
*sg_bomb-- sendSG_IOioctl which causes LSI 1068 HBA to hang *
* usage:sg_bomb<device>
* e.g.:sg_bomb/dev/sdb
* e.g.:sg_bomb/dev/sg1
*
* Modifyoffset_into_pageto adjust the degree of buffermisalignment.
Quoted 9 lines
*/
#include <
unistd.h>
#include <scsi/sg.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <stdlib.h>int
main(int argc, char* argv[])Quoted 8 lines
{ char* filename = argv[1]; unsigned int offset_into_page = 0xe40; // works: unsigned int offset_into_page = 0x0; // hangs: unsigned int offset_into_page = 0xf00; // works: unsigned int offset_into_page = 0xf04; unsigned char ata_identify_cmd[] = {0x85, 0x08, 0x0e, 0, 0, 0,
0x01,Quoted 21 lines
0, 0, 0, 0, 0, 0, 0, 0xec, 0}; unsigned char sense[32]; unsigned char* data = valloc(0x2000) + offset_into_page; struct sg_io_hdr hdr = { .interface_id = 'S', .dxfer_direction = SG_DXFER_FROM_DEV, .cmdp = ata_identify_cmd, .cmd_len = 16, .dxferp = data, .dxfer_len = 512, .sbp = sense, .mx_sb_len = sizeof(sense), .timeout = 5000, }; int fd; if ((fd = open(filename, O_RDWR|O_NONBLOCK)) < 0) perror(); return ioctl(fd, SG_IO, &hdr); }