Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-elphel
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Commits
Open sidebar
Elphel
linux-elphel
Commits
5160acf2
Commit
5160acf2
authored
Jul 23, 2019
by
Oleg Dzhimiev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
+enable_panic
parent
163a9091
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
177 additions
and
107 deletions
+177
-107
libata-eh.c
src/drivers/ata/libata-eh.c
+177
-107
No files found.
src/drivers/ata/libata-eh.c
View file @
5160acf2
...
...
@@ -25,7 +25,7 @@
*
*
* libata documentation is available via 'make {ps|pdf}docs',
* as Documentation/
DocBook/libata.*
* as Documentation/
driver-api/libata.rst
*
* Hardware documentation available from http://www.t13.org/ and
* http://www.sata-io.org/
...
...
@@ -46,6 +46,7 @@
#include <linux/libata.h>
#include <trace/events/libata.h>
#include "libata.h"
enum
{
...
...
@@ -548,6 +549,7 @@ enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
DPRINTK
(
"EXIT, ret=%d
\n
"
,
ret
);
return
ret
;
}
EXPORT_SYMBOL
(
ata_scsi_timed_out
);
static
void
ata_eh_unload
(
struct
ata_port
*
ap
)
{
...
...
@@ -605,7 +607,7 @@ void ata_scsi_error(struct Scsi_Host *host)
ata_scsi_port_error_handler
(
host
,
ap
);
/* finish or retry handled scmd's and clean up */
WARN_ON
(
host
->
host_failed
||
!
list_empty
(
&
eh_work_q
));
WARN_ON
(
!
list_empty
(
&
eh_work_q
));
DPRINTK
(
"EXIT
\n
"
);
}
...
...
@@ -643,12 +645,11 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap,
* completions are honored. A scmd is determined to have
* timed out iff its associated qc is active and not failed.
*/
spin_lock_irqsave
(
ap
->
lock
,
flags
);
if
(
ap
->
ops
->
error_handler
)
{
struct
scsi_cmnd
*
scmd
,
*
tmp
;
int
nr_timedout
=
0
;
spin_lock_irqsave
(
ap
->
lock
,
flags
);
/* This must occur under the ap->lock as we don't want
a polled recovery to race the real interrupt handler
...
...
@@ -698,12 +699,11 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap,
if
(
nr_timedout
)
__ata_port_freeze
(
ap
);
spin_unlock_irqrestore
(
ap
->
lock
,
flags
);
/* initialize eh_tries */
ap
->
eh_tries
=
ATA_EH_MAX_TRIES
;
}
else
spin_unlock_wait
(
ap
->
lock
);
}
spin_unlock_irqrestore
(
ap
->
lock
,
flags
);
}
EXPORT_SYMBOL
(
ata_scsi_cmd_error_handler
);
...
...
@@ -968,7 +968,7 @@ static void ata_eh_set_pending(struct ata_port *ap, int fastdrain)
void
ata_qc_schedule_eh
(
struct
ata_queued_cmd
*
qc
)
{
struct
ata_port
*
ap
=
qc
->
ap
;
struct
request_queue
*
q
;
struct
request_queue
*
q
=
qc
->
scsicmd
->
device
->
request_queue
;
unsigned
long
flags
;
WARN_ON
(
!
ap
->
ops
->
error_handler
);
...
...
@@ -981,12 +981,9 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
* Note that ATA_QCFLAG_FAILED is unconditionally set after
* this function completes.
*/
if
(
qc
->
scsicmd
!=
NULL
)
{
q
=
qc
->
scsicmd
->
device
->
request_queue
;
spin_lock_irqsave
(
q
->
queue_lock
,
flags
);
blk_abort_request
(
qc
->
scsicmd
->
request
);
spin_unlock_irqrestore
(
q
->
queue_lock
,
flags
);
}
}
/**
...
...
@@ -1435,7 +1432,7 @@ void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
/**
* ata_eh_done - EH action complete
* @ap: target ATA port
* @link: ATA link for which EH actions are complete
* @dev: target ATA dev for per-dev action (can be NULL)
* @action: action just completed
*
...
...
@@ -1488,46 +1485,6 @@ static const char *ata_err_string(unsigned int err_mask)
return
"unknown error"
;
}
/**
* ata_read_log_page - read a specific log page
* @dev: target device
* @log: log to read
* @page: page to read
* @buf: buffer to store read page
* @sectors: number of sectors to read
*
* Read log page using READ_LOG_EXT command.
*
* LOCKING:
* Kernel thread context (may sleep).
*
* RETURNS:
* 0 on success, AC_ERR_* mask otherwise.
*/
unsigned
int
ata_read_log_page
(
struct
ata_device
*
dev
,
u8
log
,
u8
page
,
void
*
buf
,
unsigned
int
sectors
)
{
struct
ata_taskfile
tf
;
unsigned
int
err_mask
;
DPRINTK
(
"read log page - log 0x%x, page 0x%x
\n
"
,
log
,
page
);
ata_tf_init
(
dev
,
&
tf
);
tf
.
command
=
ATA_CMD_READ_LOG_EXT
;
tf
.
lbal
=
log
;
tf
.
lbam
=
page
;
tf
.
nsect
=
sectors
;
tf
.
hob_nsect
=
sectors
>>
8
;
tf
.
flags
|=
ATA_TFLAG_ISADDR
|
ATA_TFLAG_LBA48
|
ATA_TFLAG_DEVICE
;
tf
.
protocol
=
ATA_PROT_PIO
;
err_mask
=
ata_exec_internal
(
dev
,
&
tf
,
NULL
,
DMA_FROM_DEVICE
,
buf
,
sectors
*
ATA_SECT_SIZE
,
0
);
DPRINTK
(
"EXIT, err_mask=%x
\n
"
,
err_mask
);
return
err_mask
;
}
/**
* ata_eh_read_log_10h - Read log page 10h for NCQ error details
* @dev: Device to read log page 10h from
...
...
@@ -1578,6 +1535,8 @@ static int ata_eh_read_log_10h(struct ata_device *dev,
tf
->
hob_lbah
=
buf
[
10
];
tf
->
nsect
=
buf
[
12
];
tf
->
hob_nsect
=
buf
[
13
];
if
(
ata_id_has_ncq_autosense
(
dev
->
id
))
tf
->
auxiliary
=
buf
[
14
]
<<
16
|
buf
[
15
]
<<
8
|
buf
[
16
];
return
0
;
}
...
...
@@ -1613,6 +1572,56 @@ unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
return
err_mask
;
}
/**
* ata_eh_request_sense - perform REQUEST_SENSE_DATA_EXT
* @qc: qc to perform REQUEST_SENSE_SENSE_DATA_EXT to
* @cmd: scsi command for which the sense code should be set
*
* Perform REQUEST_SENSE_DATA_EXT after the device reported CHECK
* SENSE. This function is an EH helper.
*
* LOCKING:
* Kernel thread context (may sleep).
*/
static
void
ata_eh_request_sense
(
struct
ata_queued_cmd
*
qc
,
struct
scsi_cmnd
*
cmd
)
{
struct
ata_device
*
dev
=
qc
->
dev
;
struct
ata_taskfile
tf
;
unsigned
int
err_mask
;
if
(
qc
->
ap
->
pflags
&
ATA_PFLAG_FROZEN
)
{
ata_dev_warn
(
dev
,
"sense data available but port frozen
\n
"
);
return
;
}
if
(
!
cmd
||
qc
->
flags
&
ATA_QCFLAG_SENSE_VALID
)
return
;
if
(
!
ata_id_sense_reporting_enabled
(
dev
->
id
))
{
ata_dev_warn
(
qc
->
dev
,
"sense data reporting disabled
\n
"
);
return
;
}
DPRINTK
(
"ATA request sense
\n
"
);
ata_tf_init
(
dev
,
&
tf
);
tf
.
flags
|=
ATA_TFLAG_ISADDR
|
ATA_TFLAG_DEVICE
;
tf
.
flags
|=
ATA_TFLAG_LBA
|
ATA_TFLAG_LBA48
;
tf
.
command
=
ATA_CMD_REQ_SENSE_DATA
;
tf
.
protocol
=
ATA_PROT_NODATA
;
err_mask
=
ata_exec_internal
(
dev
,
&
tf
,
NULL
,
DMA_NONE
,
NULL
,
0
,
0
);
/* Ignore err_mask; ATA_ERR might be set */
if
(
tf
.
command
&
ATA_SENSE
)
{
ata_scsi_set_sense
(
dev
,
cmd
,
tf
.
lbah
,
tf
.
lbam
,
tf
.
lbal
);
qc
->
flags
|=
ATA_QCFLAG_SENSE_VALID
;
}
else
{
ata_dev_warn
(
dev
,
"request sense failed stat %02x emask %x
\n
"
,
tf
.
command
,
err_mask
);
}
}
/**
* atapi_eh_request_sense - perform ATAPI REQUEST_SENSE
* @dev: device to perform REQUEST_SENSE to
...
...
@@ -1775,6 +1784,18 @@ void ata_eh_analyze_ncq_error(struct ata_link *link)
memcpy
(
&
qc
->
result_tf
,
&
tf
,
sizeof
(
tf
));
qc
->
result_tf
.
flags
=
ATA_TFLAG_ISADDR
|
ATA_TFLAG_LBA
|
ATA_TFLAG_LBA48
;
qc
->
err_mask
|=
AC_ERR_DEV
|
AC_ERR_NCQ
;
if
((
qc
->
result_tf
.
command
&
ATA_SENSE
)
||
qc
->
result_tf
.
auxiliary
)
{
char
sense_key
,
asc
,
ascq
;
sense_key
=
(
qc
->
result_tf
.
auxiliary
>>
16
)
&
0xff
;
asc
=
(
qc
->
result_tf
.
auxiliary
>>
8
)
&
0xff
;
ascq
=
qc
->
result_tf
.
auxiliary
&
0xff
;
ata_scsi_set_sense
(
dev
,
qc
->
scsicmd
,
sense_key
,
asc
,
ascq
);
ata_scsi_set_sense_information
(
dev
,
qc
->
scsicmd
,
&
qc
->
result_tf
);
qc
->
flags
|=
ATA_QCFLAG_SENSE_VALID
;
}
ehc
->
i
.
err_mask
&=
~
AC_ERR_DEV
;
}
...
...
@@ -1804,14 +1825,23 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
return
ATA_EH_RESET
;
}
if
(
stat
&
(
ATA_ERR
|
ATA_DF
))
if
(
stat
&
(
ATA_ERR
|
ATA_DF
))
{
qc
->
err_mask
|=
AC_ERR_DEV
;
else
/*
* Sense data reporting does not work if the
* device fault bit is set.
*/
if
(
stat
&
ATA_DF
)
stat
&=
~
ATA_SENSE
;
}
else
{
return
0
;
}
switch
(
qc
->
dev
->
class
)
{
case
ATA_DEV_ATA
:
case
ATA_DEV_ZAC
:
if
(
stat
&
ATA_SENSE
)
ata_eh_request_sense
(
qc
,
qc
->
scsicmd
);
if
(
err
&
ATA_ICRC
)
qc
->
err_mask
|=
AC_ERR_ATA_BUS
;
if
(
err
&
(
ATA_UNC
|
ATA_AMNF
))
...
...
@@ -1825,20 +1855,31 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
tmp
=
atapi_eh_request_sense
(
qc
->
dev
,
qc
->
scsicmd
->
sense_buffer
,
qc
->
result_tf
.
feature
>>
4
);
if
(
!
tmp
)
{
/* ATA_QCFLAG_SENSE_VALID is used to
* tell atapi_qc_complete() that sense
* data is already valid.
*
* TODO: interpret sense data and set
* appropriate err_mask.
*/
if
(
!
tmp
)
qc
->
flags
|=
ATA_QCFLAG_SENSE_VALID
;
}
else
else
qc
->
err_mask
|=
tmp
;
}
}
if
(
qc
->
flags
&
ATA_QCFLAG_SENSE_VALID
)
{
int
ret
=
scsi_check_sense
(
qc
->
scsicmd
);
/*
* SUCCESS here means that the sense code could
* evaluated and should be passed to the upper layers
* for correct evaluation.
* FAILED means the sense code could not interpreted
* and the device would need to be reset.
* NEEDS_RETRY and ADD_TO_MLQUEUE means that the
* command would need to be retried.
*/
if
(
ret
==
NEEDS_RETRY
||
ret
==
ADD_TO_MLQUEUE
)
{
qc
->
flags
|=
ATA_QCFLAG_RETRY
;
qc
->
err_mask
|=
AC_ERR_OTHER
;
}
else
if
(
ret
!=
SUCCESS
)
{
qc
->
err_mask
|=
AC_ERR_HSM
;
}
}
if
(
qc
->
err_mask
&
(
AC_ERR_HSM
|
AC_ERR_TIMEOUT
|
AC_ERR_ATA_BUS
))
action
|=
ATA_EH_RESET
;
...
...
@@ -1927,7 +1968,7 @@ static int speed_down_verdict_cb(struct ata_ering_entry *ent, void *void_arg)
* This is to expedite speed down decisions right after device is
* initially configured.
*
* The following
s
are speed down rules. #1 and #2 deal with
* The following are speed down rules. #1 and #2 deal with
* DUBIOUS errors.
*
* 1. If more than one DUBIOUS_ATA_BUS or DUBIOUS_TOUT_HSM errors
...
...
@@ -2189,6 +2230,7 @@ static void ata_eh_link_autopsy(struct ata_link *link)
all_err_mask
|=
qc
->
err_mask
;
if
(
qc
->
flags
&
ATA_QCFLAG_IO
)
eflags
|=
ATA_EFLAG_IS_IO
;
trace_ata_eh_link_autopsy_qc
(
qc
);
}
/* enforce default EH actions */
...
...
@@ -2223,7 +2265,7 @@ static void ata_eh_link_autopsy(struct ata_link *link)
eflags
|=
ATA_EFLAG_DUBIOUS_XFER
;
ehc
->
i
.
action
|=
ata_eh_speed_down
(
dev
,
eflags
,
all_err_mask
);
}
trace_ata_eh_link_autopsy
(
dev
,
ehc
->
i
.
action
,
all_err_mask
);
DPRINTK
(
"EXIT
\n
"
);
}
...
...
@@ -2375,6 +2417,8 @@ const char *ata_get_cmd_descript(u8 command)
{
ATA_CMD_CFA_WRITE_MULT_NE
,
"CFA WRITE MULTIPLE WITHOUT ERASE"
},
{
ATA_CMD_REQ_SENSE_DATA
,
"REQUEST SENSE DATA EXT"
},
{
ATA_CMD_SANITIZE_DEVICE
,
"SANITIZE DEVICE"
},
{
ATA_CMD_ZAC_MGMT_IN
,
"ZAC MANAGEMENT IN"
},
{
ATA_CMD_ZAC_MGMT_OUT
,
"ZAC MANAGEMENT OUT"
},
{
ATA_CMD_READ_LONG
,
"READ LONG (with retries)"
},
{
ATA_CMD_READ_LONG_ONCE
,
"READ LONG (without retries)"
},
{
ATA_CMD_WRITE_LONG
,
"WRITE LONG (with retries)"
},
...
...
@@ -2499,17 +2543,39 @@ static void ata_eh_link_report(struct ata_link *link)
[
DMA_TO_DEVICE
]
=
"out"
,
[
DMA_FROM_DEVICE
]
=
"in"
,
};
static
const
char
*
prot_str
[]
=
{
[
ATA_PROT_PIO
]
=
"pio"
,
[
ATA_PROT_DMA
]
=
"dma"
,
[
ATA_PROT_NCQ
]
=
"ncq"
,
[
ATAPI_PROT_PIO
]
=
"pio"
,
[
ATAPI_PROT_DMA
]
=
"dma"
,
};
const
char
*
prot_str
=
NULL
;
switch
(
qc
->
tf
.
protocol
)
{
case
ATA_PROT_UNKNOWN
:
prot_str
=
"unknown"
;
break
;
case
ATA_PROT_NODATA
:
prot_str
=
"nodata"
;
break
;
case
ATA_PROT_PIO
:
prot_str
=
"pio"
;
break
;
case
ATA_PROT_DMA
:
prot_str
=
"dma"
;
break
;
case
ATA_PROT_NCQ
:
prot_str
=
"ncq dma"
;
break
;
case
ATA_PROT_NCQ_NODATA
:
prot_str
=
"ncq nodata"
;
break
;
case
ATAPI_PROT_NODATA
:
prot_str
=
"nodata"
;
break
;
case
ATAPI_PROT_PIO
:
prot_str
=
"pio"
;
break
;
case
ATAPI_PROT_DMA
:
prot_str
=
"dma"
;
break
;
}
snprintf
(
data_buf
,
sizeof
(
data_buf
),
" %s %u %s"
,
prot_str
[
qc
->
tf
.
protocol
],
qc
->
nbytes
,
dma_str
[
qc
->
dma_dir
]);
prot_str
,
qc
->
nbytes
,
dma_str
[
qc
->
dma_dir
]);
}
if
(
ata_is_atapi
(
qc
->
tf
.
protocol
))
{
...
...
@@ -2551,14 +2617,15 @@ static void ata_eh_link_report(struct ata_link *link)
#ifdef CONFIG_ATA_VERBOSE_ERROR
if
(
res
->
command
&
(
ATA_BUSY
|
ATA_DRDY
|
ATA_DF
|
ATA_DRQ
|
ATA_ERR
))
{
ATA_
SENSE
|
ATA_
ERR
))
{
if
(
res
->
command
&
ATA_BUSY
)
ata_dev_err
(
qc
->
dev
,
"status: { Busy }
\n
"
);
else
ata_dev_err
(
qc
->
dev
,
"status: { %s%s%s%s}
\n
"
,
ata_dev_err
(
qc
->
dev
,
"status: { %s%s%s%s
%s
}
\n
"
,
res
->
command
&
ATA_DRDY
?
"DRDY "
:
""
,
res
->
command
&
ATA_DF
?
"DF "
:
""
,
res
->
command
&
ATA_DRQ
?
"DRQ "
:
""
,
res
->
command
&
ATA_SENSE
?
"SENSE "
:
""
,
res
->
command
&
ATA_ERR
?
"ERR "
:
""
);
}
...
...
@@ -2574,6 +2641,7 @@ static void ata_eh_link_report(struct ata_link *link)
#endif
}
}
/**
* ata_eh_report - report error handling to user
* @ap: ATA port to report EH about
...
...
@@ -3071,7 +3139,7 @@ static void ata_eh_park_issue_cmd(struct ata_device *dev, int park)
}
tf
.
flags
|=
ATA_TFLAG_DEVICE
|
ATA_TFLAG_ISADDR
;
tf
.
protocol
|
=
ATA_PROT_NODATA
;
tf
.
protocol
=
ATA_PROT_NODATA
;
err_mask
=
ata_exec_internal
(
dev
,
&
tf
,
NULL
,
DMA_NONE
,
NULL
,
0
,
0
);
if
(
park
&&
(
err_mask
||
tf
.
lbal
!=
0xc4
))
{
ata_dev_err
(
dev
,
"head unload failed!
\n
"
);
...
...
@@ -3496,6 +3564,9 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
}
}
link
->
last_lpm_change
=
jiffies
;
link
->
flags
|=
ATA_LFLAG_CHANGED
;
return
0
;
fail:
...
...
@@ -4107,7 +4178,6 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
struct
ata_link
*
link
;
struct
ata_device
*
dev
;
unsigned
long
flags
;
int
rc
=
0
;
/* are we resuming? */
spin_lock_irqsave
(
ap
->
lock
,
flags
);
...
...
@@ -4134,7 +4204,7 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
ata_acpi_set_state
(
ap
,
ap
->
pm_mesg
);
if
(
ap
->
ops
->
port_resume
)
rc
=
ap
->
ops
->
port_resume
(
ap
);
ap
->
ops
->
port_resume
(
ap
);
/* tell ACPI that we're resuming */
ata_acpi_on_resume
(
ap
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment