void ata_dev_disable(struct ata_device *dev)
{
- if (ata_dev_enabled(dev)) {
+ if (ata_dev_enabled(dev) && ata_msg_drv(dev->ap)) {
ata_dev_printk(dev, KERN_WARNING, "disabled\n");
dev->class++;
}
void ata_dev_select(struct ata_port *ap, unsigned int device,
unsigned int wait, unsigned int can_sleep)
{
- VPRINTK("ENTER, ata%u: device %u, wait %u\n",
- ap->id, device, wait);
+ if (ata_msg_probe(ap)) {
+ ata_port_printk(ap, KERN_INFO, "ata_dev_select: ENTER, ata%u: "
+ "device %u, wait %u\n",
+ ap->id, device, wait);
+ }
if (wait)
ata_wait_idle(ap);
DPRINTK("ENTER\n");
- spin_lock_irqsave(&ap->host_set->lock, flags);
+ spin_lock_irqsave(ap->lock, flags);
ap->flags |= ATA_FLAG_FLUSH_PORT_TASK;
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
DPRINTK("flush #1\n");
flush_workqueue(ata_wq);
* Cancel and flush.
*/
if (!cancel_delayed_work(&ap->port_task)) {
- DPRINTK("flush #2\n");
+ if (ata_msg_ctl(ap))
+ ata_port_printk(ap, KERN_DEBUG, "%s: flush #2\n", __FUNCTION__);
flush_workqueue(ata_wq);
}
- spin_lock_irqsave(&ap->host_set->lock, flags);
+ spin_lock_irqsave(ap->lock, flags);
ap->flags &= ~ATA_FLAG_FLUSH_PORT_TASK;
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
- DPRINTK("EXIT\n");
+ if (ata_msg_ctl(ap))
+ ata_port_printk(ap, KERN_DEBUG, "%s: EXIT\n", __FUNCTION__);
}
void ata_qc_complete_internal(struct ata_queued_cmd *qc)
*
* LOCKING:
* None. Should be called with kernel context, might sleep.
+ *
+ * RETURNS:
+ * Zero on success, AC_ERR_* mask on failure
*/
-
unsigned ata_exec_internal(struct ata_device *dev,
struct ata_taskfile *tf, const u8 *cdb,
int dma_dir, void *buf, unsigned int buflen)
unsigned int err_mask;
int rc;
- spin_lock_irqsave(&ap->host_set->lock, flags);
+ spin_lock_irqsave(ap->lock, flags);
/* no internal command while frozen */
if (ap->flags & ATA_FLAG_FROZEN) {
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
return AC_ERR_SYSTEM;
}
ata_qc_issue(qc);
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
rc = wait_for_completion_timeout(&wait, ATA_TMOUT_INTERNAL);
ata_port_flush_task(ap);
if (!rc) {
- spin_lock_irqsave(&ap->host_set->lock, flags);
+ spin_lock_irqsave(ap->lock, flags);
/* We're racing with irq here. If we lose, the
* following test prevents us from completing the qc
else
ata_qc_complete(qc);
- ata_dev_printk(dev, KERN_WARNING,
+ if (ata_msg_warn(ap))
+ ata_dev_printk(dev, KERN_WARNING,
"qc timeout (cmd 0x%x)\n", command);
}
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
}
/* do post_internal_cmd */
ap->ops->post_internal_cmd(qc);
if (qc->flags & ATA_QCFLAG_FAILED && !qc->err_mask) {
- ata_dev_printk(dev, KERN_WARNING, "zero err_mask for failed "
+ if (ata_msg_warn(ap))
+ ata_dev_printk(dev, KERN_WARNING,
+ "zero err_mask for failed "
"internal command, assuming AC_ERR_OTHER\n");
qc->err_mask |= AC_ERR_OTHER;
}
/* finish up */
- spin_lock_irqsave(&ap->host_set->lock, flags);
+ spin_lock_irqsave(ap->lock, flags);
*tf = qc->result_tf;
err_mask = qc->err_mask;
ata_port_probe(ap);
}
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
return err_mask;
}
const char *reason;
int rc;
- DPRINTK("ENTER, host %u, dev %u\n", ap->id, dev->devno);
+ if (ata_msg_ctl(ap))
+ ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n",
+ __FUNCTION__, ap->id, dev->devno);
ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */
return 0;
err_out:
- ata_dev_printk(dev, KERN_WARNING, "failed to IDENTIFY "
+ if (ata_msg_warn(ap))
+ ata_dev_printk(dev, KERN_WARNING, "failed to IDENTIFY "
"(%s, err_mask=0x%x)\n", reason, err_mask);
return rc;
}
unsigned int xfer_mask;
int i, rc;
- if (!ata_dev_enabled(dev)) {
- DPRINTK("ENTER/EXIT (host %u, dev %u) -- nodev\n",
- ap->id, dev->devno);
+ if (!ata_dev_enabled(dev) && ata_msg_info(ap)) {
+ ata_dev_printk(dev, KERN_INFO, "%s: ENTER/EXIT (host %u, dev %u) -- nodev\n",
+ __FUNCTION__, ap->id, dev->devno);
return 0;
}
- DPRINTK("ENTER, host %u, dev %u\n", ap->id, dev->devno);
+ if (ata_msg_probe(ap))
+ ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n",
+ __FUNCTION__, ap->id, dev->devno);
/* print device capabilities */
- if (print_info)
- ata_dev_printk(dev, KERN_DEBUG, "cfg 49:%04x 82:%04x 83:%04x "
+ if (ata_msg_probe(ap))
+ ata_dev_printk(dev, KERN_DEBUG, "%s: cfg 49:%04x 82:%04x 83:%04x "
"84:%04x 85:%04x 86:%04x 87:%04x 88:%04x\n",
+ __FUNCTION__,
id[49], id[82], id[83], id[84],
id[85], id[86], id[87], id[88]);
/* find max transfer mode; for printk only */
xfer_mask = ata_id_xfermask(id);
- ata_dump_id(id);
+ if (ata_msg_probe(ap))
+ ata_dump_id(id);
/* ATA-specific feature tests */
if (dev->class == ATA_DEV_ATA) {
ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
/* print device info to dmesg */
- if (print_info)
+ if (ata_msg_info(ap))
ata_dev_printk(dev, KERN_INFO, "ATA-%d, "
"max %s, %Lu sectors: %s %s\n",
ata_id_major_version(id),
}
/* print device info to dmesg */
- if (print_info)
+ if (ata_msg_info(ap))
ata_dev_printk(dev, KERN_INFO, "ATA-%d, "
"max %s, %Lu sectors: CHS %u/%u/%u\n",
ata_id_major_version(id),
if (dev->id[59] & 0x100) {
dev->multi_count = dev->id[59] & 0xff;
- DPRINTK("ata%u: dev %u multi count %u\n",
+ if (ata_msg_info(ap))
+ ata_dev_printk(dev, KERN_INFO, "ata%u: dev %u multi count %u\n",
ap->id, dev->devno, dev->multi_count);
}
rc = atapi_cdb_len(id);
if ((rc < 12) || (rc > ATAPI_CDB_LEN)) {
- ata_dev_printk(dev, KERN_WARNING,
- "unsupported CDB len\n");
+ if (ata_msg_warn(ap))
+ ata_dev_printk(dev, KERN_WARNING,
+ "unsupported CDB len\n");
rc = -EINVAL;
goto err_out_nosup;
}
}
/* print device info to dmesg */
- if (print_info)
+ if (ata_msg_info(ap))
ata_dev_printk(dev, KERN_INFO, "ATAPI, max %s%s\n",
ata_mode_string(xfer_mask),
cdb_intr_string);
/* limit bridge transfers to udma5, 200 sectors */
if (ata_dev_knobble(dev)) {
- if (print_info)
+ if (ata_msg_info(ap))
ata_dev_printk(dev, KERN_INFO,
"applying bridge limits\n");
dev->udma_mask &= ATA_UDMA5;
if (ap->ops->dev_config)
ap->ops->dev_config(ap, dev);
- DPRINTK("EXIT, drv_stat = 0x%x\n", ata_chk_status(ap));
+ if (ata_msg_probe(ap))
+ ata_dev_printk(dev, KERN_DEBUG, "%s: EXIT, drv_stat = 0x%x\n",
+ __FUNCTION__, ata_chk_status(ap));
return 0;
err_out_nosup:
- DPRINTK("EXIT, err\n");
+ if (ata_msg_probe(ap))
+ ata_dev_printk(dev, KERN_DEBUG,
+ "%s: EXIT, err\n", __FUNCTION__);
return rc;
}
down_xfermask = 0;
/* reset and determine device classes */
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- classes[i] = ATA_DEV_UNKNOWN;
+ ap->ops->phy_reset(ap);
- if (ap->ops->probe_reset) {
- rc = ap->ops->probe_reset(ap, classes);
- if (rc) {
- ata_port_printk(ap, KERN_ERR,
- "reset failed (errno=%d)\n", rc);
- return rc;
- }
- } else {
- ap->ops->phy_reset(ap);
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ dev = &ap->device[i];
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- if (!(ap->flags & ATA_FLAG_DISABLED))
- classes[i] = ap->device[i].class;
- ap->device[i].class = ATA_DEV_UNKNOWN;
- }
+ if (!(ap->flags & ATA_FLAG_DISABLED) &&
+ dev->class != ATA_DEV_UNKNOWN)
+ classes[dev->devno] = dev->class;
+ else
+ classes[dev->devno] = ATA_DEV_NONE;
- ata_port_probe(ap);
+ dev->class = ATA_DEV_UNKNOWN;
}
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- if (classes[i] == ATA_DEV_UNKNOWN)
- classes[i] = ATA_DEV_NONE;
+ ata_port_probe(ap);
/* after the reset the device state is PIO 0 and the controller
state is undefined. Record the mode */
return 0;
}
-/**
- * ata_std_probeinit - initialize probing
- * @ap: port to be probed
- *
- * @ap is about to be probed. Initialize it. This function is
- * to be used as standard callback for ata_drive_probe_reset().
- *
- * NOTE!!! Do not use this function as probeinit if a low level
- * driver implements only hardreset. Just pass NULL as probeinit
- * in that case. Using this function is probably okay but doing
- * so makes reset sequence different from the original
- * ->phy_reset implementation and Jeff nervous. :-P
- */
-void ata_std_probeinit(struct ata_port *ap)
-{
- static const unsigned long deb_timing[] = { 5, 100, 5000 };
-
- /* resume link */
- sata_phy_resume(ap, deb_timing);
-
- /* wait for device */
- if (ata_port_online(ap))
- ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
-}
-
/**
* ata_std_softreset - reset host port via ATA SRST
* @ap: port to reset
* @classes: resulting classes of attached devices
*
- * Reset host port using ATA SRST. This function is to be used
- * as standard callback for ata_drive_*_reset() functions.
+ * Reset host port using ATA SRST.
*
* LOCKING:
* Kernel thread context (may sleep)
* @class: resulting class of attached device
*
* SATA phy-reset host port using DET bits of SControl register.
- * This function is to be used as standard callback for
- * ata_drive_*_reset().
*
* LOCKING:
* Kernel thread context (may sleep)
* the device might have been reset more than once using
* different reset methods before postreset is invoked.
*
- * This function is to be used as standard callback for
- * ata_drive_*_reset().
- *
* LOCKING:
* Kernel thread context (may sleep)
*/
DPRINTK("EXIT\n");
}
-/**
- * ata_std_probe_reset - standard probe reset method
- * @ap: prot to perform probe-reset
- * @classes: resulting classes of attached devices
- *
- * The stock off-the-shelf ->probe_reset method.
- *
- * LOCKING:
- * Kernel thread context (may sleep)
- *
- * RETURNS:
- * 0 on success, -errno otherwise.
- */
-int ata_std_probe_reset(struct ata_port *ap, unsigned int *classes)
-{
- ata_reset_fn_t hardreset;
-
- hardreset = NULL;
- if (sata_scr_valid(ap))
- hardreset = sata_std_hardreset;
-
- return ata_drive_probe_reset(ap, ata_std_probeinit,
- ata_std_softreset, hardreset,
- ata_std_postreset, classes);
-}
-
-int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset,
- unsigned int *classes)
-{
- int i, rc;
-
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- classes[i] = ATA_DEV_UNKNOWN;
-
- rc = reset(ap, classes);
- if (rc)
- return rc;
-
- /* If any class isn't ATA_DEV_UNKNOWN, consider classification
- * is complete and convert all ATA_DEV_UNKNOWN to
- * ATA_DEV_NONE.
- */
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- if (classes[i] != ATA_DEV_UNKNOWN)
- break;
-
- if (i < ATA_MAX_DEVICES)
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- if (classes[i] == ATA_DEV_UNKNOWN)
- classes[i] = ATA_DEV_NONE;
-
- return 0;
-}
-
-/**
- * ata_drive_probe_reset - Perform probe reset with given methods
- * @ap: port to reset
- * @probeinit: probeinit method (can be NULL)
- * @softreset: softreset method (can be NULL)
- * @hardreset: hardreset method (can be NULL)
- * @postreset: postreset method (can be NULL)
- * @classes: resulting classes of attached devices
- *
- * Reset the specified port and classify attached devices using
- * given methods. This function prefers softreset but tries all
- * possible reset sequences to reset and classify devices. This
- * function is intended to be used for constructing ->probe_reset
- * callback by low level drivers.
- *
- * Reset methods should follow the following rules.
- *
- * - Return 0 on sucess, -errno on failure.
- * - If classification is supported, fill classes[] with
- * recognized class codes.
- * - If classification is not supported, leave classes[] alone.
- *
- * LOCKING:
- * Kernel thread context (may sleep)
- *
- * RETURNS:
- * 0 on success, -EINVAL if no reset method is avaliable, -ENODEV
- * if classification fails, and any error code from reset
- * methods.
- */
-int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit,
- ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
- ata_postreset_fn_t postreset, unsigned int *classes)
-{
- int rc = -EINVAL;
-
- ata_eh_freeze_port(ap);
-
- if (probeinit)
- probeinit(ap);
-
- if (softreset && !sata_set_spd_needed(ap)) {
- rc = ata_do_reset(ap, softreset, classes);
- if (rc == 0 && classes[0] != ATA_DEV_UNKNOWN)
- goto done;
- ata_port_printk(ap, KERN_INFO, "softreset failed, "
- "will try hardreset in 5 secs\n");
- ssleep(5);
- }
-
- if (!hardreset)
- goto done;
-
- while (1) {
- rc = ata_do_reset(ap, hardreset, classes);
- if (rc == 0) {
- if (classes[0] != ATA_DEV_UNKNOWN)
- goto done;
- break;
- }
-
- if (sata_down_spd_limit(ap))
- goto done;
-
- ata_port_printk(ap, KERN_INFO, "hardreset failed, "
- "will retry in 5 secs\n");
- ssleep(5);
- }
-
- if (softreset) {
- ata_port_printk(ap, KERN_INFO,
- "hardreset succeeded without classification, "
- "will retry softreset in 5 secs\n");
- ssleep(5);
-
- rc = ata_do_reset(ap, softreset, classes);
- }
-
- done:
- if (rc == 0) {
- if (postreset)
- postreset(ap, classes);
-
- ata_eh_thaw_port(ap);
-
- if (classes[0] == ATA_DEV_UNKNOWN)
- rc = -ENODEV;
- }
- return rc;
-}
-
/**
* ata_dev_same_device - Determine whether new ID matches configured device
* @dev: device to compare against
unsigned int nlen, rlen;
int i;
+ /* We don't support polling DMA.
+ * DMA blacklist those ATAPI devices with CDB-intr (and use PIO)
+ * if the LLDD handles only interrupts in the HSM_ST_LAST state.
+ */
+ if ((dev->ap->flags & ATA_FLAG_PIO_POLLING) &&
+ (dev->flags & ATA_DFLAG_CDB_INTR))
+ return 1;
+
ata_id_string(dev->id, model_num, ATA_ID_PROD_OFS,
sizeof(model_num));
ata_id_string(dev->id, model_rev, ATA_ID_FW_REV_OFS,
if (ap->ops->check_atapi_dma)
rc = ap->ops->check_atapi_dma(qc);
- /* We don't support polling DMA.
- * Use PIO if the LLDD handles only interrupts in
- * the HSM_ST_LAST state and the ATAPI device
- * generates CDB interrupts.
- */
- if ((ap->flags & ATA_FLAG_PIO_POLLING) &&
- (qc->dev->flags & ATA_DFLAG_CDB_INTR))
- rc = 1;
-
return rc;
}
/**
qc->n_elem = 1;
qc->orig_n_elem = 1;
qc->buf_virt = buf;
+ qc->nbytes = buflen;
sg = qc->__sg;
sg_init_one(sg, buf, buflen);
/**
* ata_mmio_data_xfer - Transfer data by MMIO
- * @dev: device for this I/O
+ * @adev: device for this I/O
* @buf: data buffer
* @buflen: buffer length
* @write_data: read/write
if (ap->ops->error_handler) {
if (in_wq) {
- spin_lock_irqsave(&ap->host_set->lock, flags);
+ spin_lock_irqsave(ap->lock, flags);
/* EH might have kicked in while host_set lock
* is released.
ata_port_freeze(ap);
}
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
} else {
if (likely(!(qc->err_mask & AC_ERR_HSM)))
ata_qc_complete(qc);
}
} else {
if (in_wq) {
- spin_lock_irqsave(&ap->host_set->lock, flags);
+ spin_lock_irqsave(ap->lock, flags);
ata_irq_on(ap);
ata_qc_complete(qc);
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
} else
ata_qc_complete(qc);
}
* hsm_task_state is changed. Hence, the following locking.
*/
if (in_wq)
- spin_lock_irqsave(&ap->host_set->lock, flags);
+ spin_lock_irqsave(ap->lock, flags);
if (qc->tf.protocol == ATA_PROT_PIO) {
/* PIO data out protocol.
atapi_send_cdb(ap, qc);
if (in_wq)
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
/* if polling, ata_pio_task() handles the rest.
* otherwise, interrupt handler takes over from here.
break;
case ATA_PROT_ATAPI_DMA:
if (qc->dev->flags & ATA_DFLAG_CDB_INTR)
- /* see ata_check_atapi_dma() */
+ /* see ata_dma_blacklisted() */
BUG();
break;
default:
if (ap->flags & ATA_FLAG_SUSPENDED) {
struct ata_device *failed_dev;
+ ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 200000);
ap->flags &= ~ATA_FLAG_SUSPENDED;
* requests which occur asynchronously. Synchronize using
* host_set lock.
*/
- spin_lock_irqsave(&ap->host_set->lock, flags);
+ spin_lock_irqsave(ap->lock, flags);
dev->flags &= ~ATA_DFLAG_INIT_MASK;
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
memset((void *)dev + ATA_DEVICE_CLEAR_OFFSET, 0,
sizeof(*dev) - ATA_DEVICE_CLEAR_OFFSET);
host->unique_id = ata_unique_id++;
host->max_cmd_len = 12;
+ ap->lock = &host_set->lock;
ap->flags = ATA_FLAG_DISABLED;
ap->id = host->unique_id;
ap->host = host;
ap->hw_sata_spd_limit = UINT_MAX;
ap->active_tag = ATA_TAG_POISON;
ap->last_ctl = 0xFF;
- ap->msg_enable = ATA_MSG_DRV;
+
+#if defined(ATA_VERBOSE_DEBUG)
+ /* turn on all debugging levels */
+ ap->msg_enable = 0x00FF;
+#elif defined(ATA_DEBUG)
+ ap->msg_enable = ATA_MSG_DRV | ATA_MSG_INFO | ATA_MSG_CTL | ATA_MSG_WARN | ATA_MSG_ERR;
+#else
+ ap->msg_enable = ATA_MSG_DRV | ATA_MSG_ERR | ATA_MSG_WARN;
+#endif
INIT_WORK(&ap->port_task, NULL, NULL);
+ INIT_WORK(&ap->hotplug_task, ata_scsi_hotplug, ap);
+ INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan, ap);
INIT_LIST_HEAD(&ap->eh_done_q);
init_waitqueue_head(&ap->eh_wait_q);
DPRINTK("ENTER\n");
- if (!ent->port_ops->probe_reset &&
+ if (!ent->port_ops->error_handler &&
!(ent->host_flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST))) {
printk(KERN_ERR "ata%u: no reset mechanism available\n",
port_no);
* RETURNS:
* Number of ports registered. Zero on error (no ports registered).
*/
-
int ata_device_add(const struct ata_probe_ent *ent)
{
unsigned int count = 0, i;
struct device *dev = ent->dev;
struct ata_host_set *host_set;
+ int rc;
DPRINTK("ENTER\n");
/* alloc a container for our list of ATA ports (buses) */
goto err_free_ret;
/* obtain irq, that is shared between channels */
- if (request_irq(ent->irq, ent->port_ops->irq_handler, ent->irq_flags,
- DRV_NAME, host_set))
+ rc = request_irq(ent->irq, ent->port_ops->irq_handler, ent->irq_flags,
+ DRV_NAME, host_set);
+ if (rc) {
+ dev_printk(KERN_ERR, dev, "irq %lu request failed: %d\n",
+ ent->irq, rc);
goto err_out;
+ }
/* perform each probe synchronously */
DPRINTK("probe begin\n");
}
ap->sata_spd_limit = ap->hw_sata_spd_limit;
- DPRINTK("ata%u: bus probe begin\n", ap->id);
- rc = ata_bus_probe(ap);
- DPRINTK("ata%u: bus probe end\n", ap->id);
-
- if (rc) {
- /* FIXME: do something useful here?
- * Current libata behavior will
- * tear down everything when
- * the module is removed
- * or the h/w is unplugged.
- */
- }
-
rc = scsi_add_host(ap->host, dev);
if (rc) {
ata_port_printk(ap, KERN_ERR, "scsi_add_host failed\n");
* at the very least
*/
}
+
+ if (ap->ops->error_handler) {
+ unsigned long flags;
+
+ ata_port_probe(ap);
+
+ /* kick EH for boot probing */
+ spin_lock_irqsave(ap->lock, flags);
+
+ ap->eh_info.probe_mask = (1 << ATA_MAX_DEVICES) - 1;
+ ap->eh_info.action |= ATA_EH_SOFTRESET;
+
+ ap->flags |= ATA_FLAG_LOADING;
+ ata_port_schedule_eh(ap);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ /* wait for EH to finish */
+ ata_port_wait_eh(ap);
+ } else {
+ DPRINTK("ata%u: bus probe begin\n", ap->id);
+ rc = ata_bus_probe(ap);
+ DPRINTK("ata%u: bus probe end\n", ap->id);
+
+ if (rc) {
+ /* FIXME: do something useful here?
+ * Current libata behavior will
+ * tear down everything when
+ * the module is removed
+ * or the h/w is unplugged.
+ */
+ }
+ }
}
/* probes are done, now scan each port's disk(s) */
return 0;
}
+/**
+ * ata_port_detach - Detach ATA port in prepration of device removal
+ * @ap: ATA port to be detached
+ *
+ * Detach all ATA devices and the associated SCSI devices of @ap;
+ * then, remove the associated SCSI host. @ap is guaranteed to
+ * be quiescent on return from this function.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+void ata_port_detach(struct ata_port *ap)
+{
+ unsigned long flags;
+ int i;
+
+ if (!ap->ops->error_handler)
+ return;
+
+ /* tell EH we're leaving & flush EH */
+ spin_lock_irqsave(ap->lock, flags);
+ ap->flags |= ATA_FLAG_UNLOADING;
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ ata_port_wait_eh(ap);
+
+ /* EH is now guaranteed to see UNLOADING, so no new device
+ * will be attached. Disable all existing devices.
+ */
+ spin_lock_irqsave(ap->lock, flags);
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ ata_dev_disable(&ap->device[i]);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ /* Final freeze & EH. All in-flight commands are aborted. EH
+ * will be skipped and retrials will be terminated with bad
+ * target.
+ */
+ spin_lock_irqsave(ap->lock, flags);
+ ata_port_freeze(ap); /* won't be thawed */
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ ata_port_wait_eh(ap);
+
+ /* Flush hotplug task. The sequence is similar to
+ * ata_port_flush_task().
+ */
+ flush_workqueue(ata_aux_wq);
+ cancel_delayed_work(&ap->hotplug_task);
+ flush_workqueue(ata_aux_wq);
+
+ /* remove the associated SCSI host */
+ scsi_remove_host(ap->host);
+}
+
/**
* ata_host_set_remove - PCI layer callback for device removal
* @host_set: ATA host set that was removed
void ata_host_set_remove(struct ata_host_set *host_set)
{
- struct ata_port *ap;
unsigned int i;
- for (i = 0; i < host_set->n_ports; i++) {
- ap = host_set->ports[i];
- scsi_remove_host(ap->host);
- }
+ for (i = 0; i < host_set->n_ports; i++)
+ ata_port_detach(host_set->ports[i]);
free_irq(host_set->irq, host_set);
for (i = 0; i < host_set->n_ports; i++) {
- ap = host_set->ports[i];
+ struct ata_port *ap = host_set->ports[i];
ata_scsi_release(ap->host);
{
struct device *dev = pci_dev_to_dev(pdev);
struct ata_host_set *host_set = dev_get_drvdata(dev);
+ struct ata_host_set *host_set2 = host_set->next;
ata_host_set_remove(host_set);
+ if (host_set2)
+ ata_host_set_remove(host_set2);
+
pci_release_regions(pdev);
pci_disable_device(pdev);
dev_set_drvdata(dev, NULL);
EXPORT_SYMBOL_GPL(ata_std_bios_param);
EXPORT_SYMBOL_GPL(ata_std_ports);
EXPORT_SYMBOL_GPL(ata_device_add);
+EXPORT_SYMBOL_GPL(ata_port_detach);
EXPORT_SYMBOL_GPL(ata_host_set_remove);
EXPORT_SYMBOL_GPL(ata_sg_init);
EXPORT_SYMBOL_GPL(ata_sg_init_one);
EXPORT_SYMBOL_GPL(sata_phy_reset);
EXPORT_SYMBOL_GPL(__sata_phy_reset);
EXPORT_SYMBOL_GPL(ata_bus_reset);
-EXPORT_SYMBOL_GPL(ata_std_probeinit);
EXPORT_SYMBOL_GPL(ata_std_prereset);
EXPORT_SYMBOL_GPL(ata_std_softreset);
EXPORT_SYMBOL_GPL(sata_std_hardreset);
EXPORT_SYMBOL_GPL(ata_std_postreset);
-EXPORT_SYMBOL_GPL(ata_std_probe_reset);
-EXPORT_SYMBOL_GPL(ata_drive_probe_reset);
EXPORT_SYMBOL_GPL(ata_dev_revalidate);
EXPORT_SYMBOL_GPL(ata_dev_classify);
EXPORT_SYMBOL_GPL(ata_dev_pair);
EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
+EXPORT_SYMBOL_GPL(ata_scsi_slave_destroy);
EXPORT_SYMBOL_GPL(ata_scsi_change_queue_depth);
EXPORT_SYMBOL_GPL(ata_scsi_release);
EXPORT_SYMBOL_GPL(ata_host_intr);