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 | c2bd58047b9b5c91a3b0a851de66a877f2eb7ae3 (patch) | |
tree | aaaa1cc9da06699c6d68e88dba5e304ae5788a3c /drivers/scsi/libata-core.c | |
parent | a62c0fc526c344d8163f7a9e45e68cc63826ffd3 (diff) |
[PATCH] libata: implement standard reset component operations and ->probe_reset
Implement SRST, COMRESET and standard postreset component operations
for ata_drive_probe_reset(), and use these three functions to
implement ata_std_probe_reset.
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 | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index cf91fdc08ef6..b369dbd7cb23 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c | |||
@@ -2233,6 +2233,208 @@ err_out: | |||
2233 | DPRINTK("EXIT\n"); | 2233 | DPRINTK("EXIT\n"); |
2234 | } | 2234 | } |
2235 | 2235 | ||
2236 | /** | ||
2237 | * ata_std_softreset - reset host port via ATA SRST | ||
2238 | * @ap: port to reset | ||
2239 | * @verbose: fail verbosely | ||
2240 | * @classes: resulting classes of attached devices | ||
2241 | * | ||
2242 | * Reset host port using ATA SRST. This function is to be used | ||
2243 | * as standard callback for ata_drive_*_reset() functions. | ||
2244 | * | ||
2245 | * LOCKING: | ||
2246 | * Kernel thread context (may sleep) | ||
2247 | * | ||
2248 | * RETURNS: | ||
2249 | * 0 on success, -errno otherwise. | ||
2250 | */ | ||
2251 | int ata_std_softreset(struct ata_port *ap, int verbose, unsigned int *classes) | ||
2252 | { | ||
2253 | unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; | ||
2254 | unsigned int devmask = 0, err_mask; | ||
2255 | u8 err; | ||
2256 | |||
2257 | DPRINTK("ENTER\n"); | ||
2258 | |||
2259 | /* determine if device 0/1 are present */ | ||
2260 | if (ata_devchk(ap, 0)) | ||
2261 | devmask |= (1 << 0); | ||
2262 | if (slave_possible && ata_devchk(ap, 1)) | ||
2263 | devmask |= (1 << 1); | ||
2264 | |||
2265 | /* devchk reports device presence without actual device on | ||
2266 | * most SATA controllers. Check SStatus and turn devmask off | ||
2267 | * if link is offline. Note that we should continue resetting | ||
2268 | * even when it seems like there's no device. | ||
2269 | */ | ||
2270 | if (ap->ops->scr_read && !sata_dev_present(ap)) | ||
2271 | devmask = 0; | ||
2272 | |||
2273 | /* select device 0 again */ | ||
2274 | ap->ops->dev_select(ap, 0); | ||
2275 | |||
2276 | /* issue bus reset */ | ||
2277 | DPRINTK("about to softreset, devmask=%x\n", devmask); | ||
2278 | err_mask = ata_bus_softreset(ap, devmask); | ||
2279 | if (err_mask) { | ||
2280 | if (verbose) | ||
2281 | printk(KERN_ERR "ata%u: SRST failed (err_mask=0x%x)\n", | ||
2282 | ap->id, err_mask); | ||
2283 | else | ||
2284 | DPRINTK("EXIT, softreset failed (err_mask=0x%x)\n", | ||
2285 | err_mask); | ||
2286 | return -EIO; | ||
2287 | } | ||
2288 | |||
2289 | /* determine by signature whether we have ATA or ATAPI devices */ | ||
2290 | classes[0] = ata_dev_try_classify(ap, 0, &err); | ||
2291 | if (slave_possible && err != 0x81) | ||
2292 | classes[1] = ata_dev_try_classify(ap, 1, &err); | ||
2293 | |||
2294 | DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]); | ||
2295 | return 0; | ||
2296 | } | ||
2297 | |||
2298 | /** | ||
2299 | * sata_std_hardreset - reset host port via SATA phy reset | ||
2300 | * @ap: port to reset | ||
2301 | * @verbose: fail verbosely | ||
2302 | * @class: resulting class of attached device | ||
2303 | * | ||
2304 | * SATA phy-reset host port using DET bits of SControl register. | ||
2305 | * This function is to be used as standard callback for | ||
2306 | * ata_drive_*_reset(). | ||
2307 | * | ||
2308 | * LOCKING: | ||
2309 | * Kernel thread context (may sleep) | ||
2310 | * | ||
2311 | * RETURNS: | ||
2312 | * 0 on success, -errno otherwise. | ||
2313 | */ | ||
2314 | int sata_std_hardreset(struct ata_port *ap, int verbose, unsigned int *class) | ||
2315 | { | ||
2316 | u32 sstatus, serror; | ||
2317 | unsigned long timeout = jiffies + (HZ * 5); | ||
2318 | |||
2319 | DPRINTK("ENTER\n"); | ||
2320 | |||
2321 | /* Issue phy wake/reset */ | ||
2322 | scr_write_flush(ap, SCR_CONTROL, 0x301); | ||
2323 | |||
2324 | /* | ||
2325 | * Couldn't find anything in SATA I/II specs, but AHCI-1.1 | ||
2326 | * 10.4.2 says at least 1 ms. | ||
2327 | */ | ||
2328 | msleep(1); | ||
2329 | |||
2330 | scr_write_flush(ap, SCR_CONTROL, 0x300); | ||
2331 | |||
2332 | /* Wait for phy to become ready, if necessary. */ | ||
2333 | do { | ||
2334 | msleep(200); | ||
2335 | sstatus = scr_read(ap, SCR_STATUS); | ||
2336 | if ((sstatus & 0xf) != 1) | ||
2337 | break; | ||
2338 | } while (time_before(jiffies, timeout)); | ||
2339 | |||
2340 | /* Clear SError */ | ||
2341 | serror = scr_read(ap, SCR_ERROR); | ||
2342 | scr_write(ap, SCR_ERROR, serror); | ||
2343 | |||
2344 | /* TODO: phy layer with polling, timeouts, etc. */ | ||
2345 | if (!sata_dev_present(ap)) { | ||
2346 | *class = ATA_DEV_NONE; | ||
2347 | DPRINTK("EXIT, link offline\n"); | ||
2348 | return 0; | ||
2349 | } | ||
2350 | |||
2351 | if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) { | ||
2352 | if (verbose) | ||
2353 | printk(KERN_ERR "ata%u: COMRESET failed " | ||
2354 | "(device not ready)\n", ap->id); | ||
2355 | else | ||
2356 | DPRINTK("EXIT, device not ready\n"); | ||
2357 | return -EIO; | ||
2358 | } | ||
2359 | |||
2360 | *class = ata_dev_try_classify(ap, 0, NULL); | ||
2361 | |||
2362 | DPRINTK("EXIT, class=%u\n", *class); | ||
2363 | return 0; | ||
2364 | } | ||
2365 | |||
2366 | /** | ||
2367 | * ata_std_postreset - standard postreset callback | ||
2368 | * @ap: the target ata_port | ||
2369 | * @classes: classes of attached devices | ||
2370 | * | ||
2371 | * This function is invoked after a successful reset. Note that | ||
2372 | * the device might have been reset more than once using | ||
2373 | * different reset methods before postreset is invoked. | ||
2374 | * postreset is also reponsible for setting cable type. | ||
2375 | * | ||
2376 | * This function is to be used as standard callback for | ||
2377 | * ata_drive_*_reset(). | ||
2378 | * | ||
2379 | * LOCKING: | ||
2380 | * Kernel thread context (may sleep) | ||
2381 | */ | ||
2382 | void ata_std_postreset(struct ata_port *ap, unsigned int *classes) | ||
2383 | { | ||
2384 | DPRINTK("ENTER\n"); | ||
2385 | |||
2386 | /* set cable type */ | ||
2387 | if (ap->cbl == ATA_CBL_NONE && ap->flags & ATA_FLAG_SATA) | ||
2388 | ap->cbl = ATA_CBL_SATA; | ||
2389 | |||
2390 | /* print link status */ | ||
2391 | if (ap->cbl == ATA_CBL_SATA) | ||
2392 | sata_print_link_status(ap); | ||
2393 | |||
2394 | /* bail out if no device is present */ | ||
2395 | if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) { | ||
2396 | DPRINTK("EXIT, no device\n"); | ||
2397 | return; | ||
2398 | } | ||
2399 | |||
2400 | /* is double-select really necessary? */ | ||
2401 | if (classes[0] != ATA_DEV_NONE) | ||
2402 | ap->ops->dev_select(ap, 1); | ||
2403 | if (classes[1] != ATA_DEV_NONE) | ||
2404 | ap->ops->dev_select(ap, 0); | ||
2405 | |||
2406 | /* re-enable interrupts & set up device control */ | ||
2407 | if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */ | ||
2408 | ata_irq_on(ap); | ||
2409 | |||
2410 | DPRINTK("EXIT\n"); | ||
2411 | } | ||
2412 | |||
2413 | /** | ||
2414 | * ata_std_probe_reset - standard probe reset method | ||
2415 | * @ap: prot to perform probe-reset | ||
2416 | * @classes: resulting classes of attached devices | ||
2417 | * | ||
2418 | * The stock off-the-shelf ->probe_reset method. | ||
2419 | * | ||
2420 | * LOCKING: | ||
2421 | * Kernel thread context (may sleep) | ||
2422 | * | ||
2423 | * RETURNS: | ||
2424 | * 0 on success, -errno otherwise. | ||
2425 | */ | ||
2426 | int ata_std_probe_reset(struct ata_port *ap, unsigned int *classes) | ||
2427 | { | ||
2428 | ata_reset_fn_t hardreset; | ||
2429 | |||
2430 | hardreset = NULL; | ||
2431 | if (ap->cbl == ATA_CBL_SATA && ap->ops->scr_read) | ||
2432 | hardreset = sata_std_hardreset; | ||
2433 | |||
2434 | return ata_drive_probe_reset(ap, ata_std_softreset, hardreset, | ||
2435 | ata_std_postreset, classes); | ||
2436 | } | ||
2437 | |||
2236 | static int do_probe_reset(struct ata_port *ap, ata_reset_fn_t reset, | 2438 | static int do_probe_reset(struct ata_port *ap, ata_reset_fn_t reset, |
2237 | ata_postreset_fn_t postreset, | 2439 | ata_postreset_fn_t postreset, |
2238 | unsigned int *classes) | 2440 | unsigned int *classes) |
@@ -5268,6 +5470,10 @@ EXPORT_SYMBOL_GPL(ata_port_probe); | |||
5268 | EXPORT_SYMBOL_GPL(sata_phy_reset); | 5470 | EXPORT_SYMBOL_GPL(sata_phy_reset); |
5269 | EXPORT_SYMBOL_GPL(__sata_phy_reset); | 5471 | EXPORT_SYMBOL_GPL(__sata_phy_reset); |
5270 | EXPORT_SYMBOL_GPL(ata_bus_reset); | 5472 | EXPORT_SYMBOL_GPL(ata_bus_reset); |
5473 | EXPORT_SYMBOL_GPL(ata_std_softreset); | ||
5474 | EXPORT_SYMBOL_GPL(sata_std_hardreset); | ||
5475 | EXPORT_SYMBOL_GPL(ata_std_postreset); | ||
5476 | EXPORT_SYMBOL_GPL(ata_std_probe_reset); | ||
5271 | EXPORT_SYMBOL_GPL(ata_drive_probe_reset); | 5477 | EXPORT_SYMBOL_GPL(ata_drive_probe_reset); |
5272 | EXPORT_SYMBOL_GPL(ata_port_disable); | 5478 | EXPORT_SYMBOL_GPL(ata_port_disable); |
5273 | EXPORT_SYMBOL_GPL(ata_ratelimit); | 5479 | EXPORT_SYMBOL_GPL(ata_ratelimit); |