diff options
author | Tejun Heo <htejun@gmail.com> | 2006-01-24 03:05:22 -0500 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2006-01-27 20:58:34 -0500 |
commit | a62c0fc526c344d8163f7a9e45e68cc63826ffd3 (patch) | |
tree | d803a14848eb785f63b5f9e2d0b3f19afa0bda9d /drivers/scsi/libata-core.c | |
parent | c19ba8af4f104cca28d548cac55c128b28dd31fb (diff) |
[PATCH] libata: implement ata_drive_probe_reset()
Most low level drivers share supported reset/classify actions and
sequence. This patch implements ata_drive_probe_reset() which helps
constructing ->probe_reset from three component operations -
softreset, hardreset and postreset. This minimizes duplicate code and
yet allows flexibility if needed. The three component operations can
also be shared by EH later.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
Diffstat (limited to 'drivers/scsi/libata-core.c')
-rw-r--r-- | drivers/scsi/libata-core.c | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 147e1461062d..cf91fdc08ef6 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c | |||
@@ -2233,6 +2233,94 @@ err_out: | |||
2233 | DPRINTK("EXIT\n"); | 2233 | DPRINTK("EXIT\n"); |
2234 | } | 2234 | } |
2235 | 2235 | ||
2236 | static int do_probe_reset(struct ata_port *ap, ata_reset_fn_t reset, | ||
2237 | ata_postreset_fn_t postreset, | ||
2238 | unsigned int *classes) | ||
2239 | { | ||
2240 | int i, rc; | ||
2241 | |||
2242 | for (i = 0; i < ATA_MAX_DEVICES; i++) | ||
2243 | classes[i] = ATA_DEV_UNKNOWN; | ||
2244 | |||
2245 | rc = reset(ap, 0, classes); | ||
2246 | if (rc) | ||
2247 | return rc; | ||
2248 | |||
2249 | /* If any class isn't ATA_DEV_UNKNOWN, consider classification | ||
2250 | * is complete and convert all ATA_DEV_UNKNOWN to | ||
2251 | * ATA_DEV_NONE. | ||
2252 | */ | ||
2253 | for (i = 0; i < ATA_MAX_DEVICES; i++) | ||
2254 | if (classes[i] != ATA_DEV_UNKNOWN) | ||
2255 | break; | ||
2256 | |||
2257 | if (i < ATA_MAX_DEVICES) | ||
2258 | for (i = 0; i < ATA_MAX_DEVICES; i++) | ||
2259 | if (classes[i] == ATA_DEV_UNKNOWN) | ||
2260 | classes[i] = ATA_DEV_NONE; | ||
2261 | |||
2262 | if (postreset) | ||
2263 | postreset(ap, classes); | ||
2264 | |||
2265 | return classes[0] != ATA_DEV_UNKNOWN ? 0 : -ENODEV; | ||
2266 | } | ||
2267 | |||
2268 | /** | ||
2269 | * ata_drive_probe_reset - Perform probe reset with given methods | ||
2270 | * @ap: port to reset | ||
2271 | * @softreset: softreset method (can be NULL) | ||
2272 | * @hardreset: hardreset method (can be NULL) | ||
2273 | * @postreset: postreset method (can be NULL) | ||
2274 | * @classes: resulting classes of attached devices | ||
2275 | * | ||
2276 | * Reset the specified port and classify attached devices using | ||
2277 | * given methods. This function prefers softreset but tries all | ||
2278 | * possible reset sequences to reset and classify devices. This | ||
2279 | * function is intended to be used for constructing ->probe_reset | ||
2280 | * callback by low level drivers. | ||
2281 | * | ||
2282 | * Reset methods should follow the following rules. | ||
2283 | * | ||
2284 | * - Return 0 on sucess, -errno on failure. | ||
2285 | * - If classification is supported, fill classes[] with | ||
2286 | * recognized class codes. | ||
2287 | * - If classification is not supported, leave classes[] alone. | ||
2288 | * - If verbose is non-zero, print error message on failure; | ||
2289 | * otherwise, shut up. | ||
2290 | * | ||
2291 | * LOCKING: | ||
2292 | * Kernel thread context (may sleep) | ||
2293 | * | ||
2294 | * RETURNS: | ||
2295 | * 0 on success, -EINVAL if no reset method is avaliable, -ENODEV | ||
2296 | * if classification fails, and any error code from reset | ||
2297 | * methods. | ||
2298 | */ | ||
2299 | int ata_drive_probe_reset(struct ata_port *ap, | ||
2300 | ata_reset_fn_t softreset, ata_reset_fn_t hardreset, | ||
2301 | ata_postreset_fn_t postreset, unsigned int *classes) | ||
2302 | { | ||
2303 | int rc = -EINVAL; | ||
2304 | |||
2305 | if (softreset) { | ||
2306 | rc = do_probe_reset(ap, softreset, postreset, classes); | ||
2307 | if (rc == 0) | ||
2308 | return 0; | ||
2309 | } | ||
2310 | |||
2311 | if (!hardreset) | ||
2312 | return rc; | ||
2313 | |||
2314 | rc = do_probe_reset(ap, hardreset, postreset, classes); | ||
2315 | if (rc == 0 || rc != -ENODEV) | ||
2316 | return rc; | ||
2317 | |||
2318 | if (softreset) | ||
2319 | rc = do_probe_reset(ap, softreset, postreset, classes); | ||
2320 | |||
2321 | return rc; | ||
2322 | } | ||
2323 | |||
2236 | static void ata_pr_blacklisted(const struct ata_port *ap, | 2324 | static void ata_pr_blacklisted(const struct ata_port *ap, |
2237 | const struct ata_device *dev) | 2325 | const struct ata_device *dev) |
2238 | { | 2326 | { |
@@ -5180,6 +5268,7 @@ EXPORT_SYMBOL_GPL(ata_port_probe); | |||
5180 | EXPORT_SYMBOL_GPL(sata_phy_reset); | 5268 | EXPORT_SYMBOL_GPL(sata_phy_reset); |
5181 | EXPORT_SYMBOL_GPL(__sata_phy_reset); | 5269 | EXPORT_SYMBOL_GPL(__sata_phy_reset); |
5182 | EXPORT_SYMBOL_GPL(ata_bus_reset); | 5270 | EXPORT_SYMBOL_GPL(ata_bus_reset); |
5271 | EXPORT_SYMBOL_GPL(ata_drive_probe_reset); | ||
5183 | EXPORT_SYMBOL_GPL(ata_port_disable); | 5272 | EXPORT_SYMBOL_GPL(ata_port_disable); |
5184 | EXPORT_SYMBOL_GPL(ata_ratelimit); | 5273 | EXPORT_SYMBOL_GPL(ata_ratelimit); |
5185 | EXPORT_SYMBOL_GPL(ata_busy_sleep); | 5274 | EXPORT_SYMBOL_GPL(ata_busy_sleep); |