static unsigned int ata_busy_sleep (struct ata_port *ap,
unsigned long tmout_pat,
unsigned long tmout);
+static void ata_dev_init_params(struct ata_port *ap, struct ata_device *dev);
static void ata_set_mode(struct ata_port *ap);
static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev);
static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift);
static void ata_dev_identify(struct ata_port *ap, unsigned int device)
{
struct ata_device *dev = &ap->device[device];
- unsigned int i;
+ unsigned int major_version;
u16 tmp;
unsigned long xfer_modes;
u8 status;
* common ATA, ATAPI feature tests
*/
- /* we require LBA and DMA support (bits 8 & 9 of word 49) */
- if (!ata_id_has_dma(dev->id) || !ata_id_has_lba(dev->id)) {
- printk(KERN_DEBUG "ata%u: no dma/lba\n", ap->id);
+ /* we require DMA support (bits 8 of word 49) */
+ if (!ata_id_has_dma(dev->id)) {
+ printk(KERN_DEBUG "ata%u: no dma\n", ap->id);
goto err_out_nosup;
}
if (!ata_id_is_ata(dev->id)) /* sanity check */
goto err_out_nosup;
+ /* get major version */
tmp = dev->id[ATA_ID_MAJOR_VER];
- for (i = 14; i >= 1; i--)
- if (tmp & (1 << i))
+ for (major_version = 14; major_version >= 1; major_version--)
+ if (tmp & (1 << major_version))
break;
- /* we require at least ATA-3 */
- if (i < 3) {
- printk(KERN_DEBUG "ata%u: no ATA-3\n", ap->id);
- goto err_out_nosup;
- }
+ /*
+ * The exact sequence expected by certain pre-ATA4 drives is:
+ * SRST RESET
+ * IDENTIFY
+ * INITIALIZE DEVICE PARAMETERS
+ * anything else..
+ * Some drives were very specific about that exact sequence.
+ */
+ if (major_version < 4 || (!ata_id_has_lba(dev->id)))
+ ata_dev_init_params(ap, dev);
+
+ if (ata_id_has_lba(dev->id)) {
+ dev->flags |= ATA_DFLAG_LBA;
+
+ if (ata_id_has_lba48(dev->id)) {
+ dev->flags |= ATA_DFLAG_LBA48;
+ dev->n_sectors = ata_id_u64(dev->id, 100);
+ } else {
+ dev->n_sectors = ata_id_u32(dev->id, 60);
+ }
+
+ /* print device info to dmesg */
+ printk(KERN_INFO "ata%u: dev %u ATA-%d, max %s, %Lu sectors:%s\n",
+ ap->id, device,
+ major_version,
+ ata_mode_string(xfer_modes),
+ (unsigned long long)dev->n_sectors,
+ dev->flags & ATA_DFLAG_LBA48 ? " LBA48" : " LBA");
+ } else {
+ /* CHS */
+
+ /* Default translation */
+ dev->cylinders = dev->id[1];
+ dev->heads = dev->id[3];
+ dev->sectors = dev->id[6];
+ dev->n_sectors = dev->cylinders * dev->heads * dev->sectors;
+
+ if (ata_id_current_chs_valid(dev->id)) {
+ /* Current CHS translation is valid. */
+ dev->cylinders = dev->id[54];
+ dev->heads = dev->id[55];
+ dev->sectors = dev->id[56];
+
+ dev->n_sectors = ata_id_u32(dev->id, 57);
+ }
+
+ /* print device info to dmesg */
+ printk(KERN_INFO "ata%u: dev %u ATA-%d, max %s, %Lu sectors: CHS %d/%d/%d\n",
+ ap->id, device,
+ major_version,
+ ata_mode_string(xfer_modes),
+ (unsigned long long)dev->n_sectors,
+ (int)dev->cylinders, (int)dev->heads, (int)dev->sectors);
- if (ata_id_has_lba48(dev->id)) {
- dev->flags |= ATA_DFLAG_LBA48;
- dev->n_sectors = ata_id_u64(dev->id, 100);
- } else {
- dev->n_sectors = ata_id_u32(dev->id, 60);
}
ap->host->max_cmd_len = 16;
-
- /* print device info to dmesg */
- printk(KERN_INFO "ata%u: dev %u ATA, max %s, %Lu sectors:%s\n",
- ap->id, device,
- ata_mode_string(xfer_modes),
- (unsigned long long)dev->n_sectors,
- dev->flags & ATA_DFLAG_LBA48 ? " lba48" : "");
}
/* ATAPI-specific feature tests */
DPRINTK("EXIT\n");
}
+/**
+ * ata_dev_init_params - Issue INIT DEV PARAMS command
+ * @ap: Port associated with device @dev
+ * @dev: Device to which command will be sent
+ *
+ * LOCKING:
+ */
+
+static void ata_dev_init_params(struct ata_port *ap, struct ata_device *dev)
+{
+ DECLARE_COMPLETION(wait);
+ struct ata_queued_cmd *qc;
+ int rc;
+ unsigned long flags;
+ u16 sectors = dev->id[6];
+ u16 heads = dev->id[3];
+
+ /* Number of sectors per track 1-255. Number of heads 1-16 */
+ if (sectors < 1 || sectors > 255 || heads < 1 || heads > 16)
+ return;
+
+ /* set up init dev params taskfile */
+ DPRINTK("init dev params \n");
+
+ qc = ata_qc_new_init(ap, dev);
+ BUG_ON(qc == NULL);
+
+ qc->tf.command = ATA_CMD_INIT_DEV_PARAMS;
+ qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ qc->tf.protocol = ATA_PROT_NODATA;
+ qc->tf.nsect = sectors;
+ qc->tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 1 */
+
+ qc->waiting = &wait;
+ qc->complete_fn = ata_qc_complete_noop;
+
+ spin_lock_irqsave(&ap->host_set->lock, flags);
+ rc = ata_qc_issue(qc);
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+ if (rc)
+ ata_port_disable(ap);
+ else
+ wait_for_completion(&wait);
+
+ DPRINTK("EXIT\n");
+}
+
/**
* ata_sg_clean - Unmap DMA memory associated with command
* @qc: Command containing DMA memory to be released
*
* LOCKING:
* None. (executing in kernel thread context)
+ *
+ * RETURNS:
+ * Non-zero if qc completed, zero otherwise.
*/
- static void ata_pio_complete (struct ata_port *ap)
+ static int ata_pio_complete (struct ata_port *ap)
{
struct ata_queued_cmd *qc;
u8 drv_stat;
if (drv_stat & (ATA_BUSY | ATA_DRQ)) {
ap->pio_task_state = PIO_ST_LAST_POLL;
ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO;
- return;
+ return 0;
}
}
drv_stat = ata_wait_idle(ap);
if (!ata_ok(drv_stat)) {
ap->pio_task_state = PIO_ST_ERR;
- return;
+ return 0;
}
qc = ata_qc_from_tag(ap, ap->active_tag);
ap->pio_task_state = PIO_ST_IDLE;
ata_poll_qc_complete(qc, drv_stat);
+
+ /* another command may start at this point */
+
+ return 1;
}
next_sg:
if (unlikely(qc->cursg >= qc->n_elem)) {
- /*
+ /*
* The end of qc->sg is reached and the device expects
* more data to transfer. In order not to overrun qc->sg
* and fulfill length specified in the byte count register,
unsigned int i;
if (words) /* warning if bytes > 1 */
- printk(KERN_WARNING "ata%u: %u bytes trailing data\n",
+ printk(KERN_WARNING "ata%u: %u bytes trailing data\n",
ap->id, bytes);
for (i = 0; i < words; i++)
if (is_atapi_taskfile(&qc->tf)) {
/* no more data to transfer or unsupported ATAPI command */
if ((status & ATA_DRQ) == 0) {
- ap->pio_task_state = PIO_ST_IDLE;
-
- ata_poll_qc_complete(qc, status);
+ ap->pio_task_state = PIO_ST_LAST;
return;
}
static void ata_pio_task(void *_data)
{
struct ata_port *ap = _data;
- unsigned long timeout = 0;
+ unsigned long timeout;
+ int qc_completed;
+
+ fsm_start:
+ timeout = 0;
+ qc_completed = 0;
switch (ap->pio_task_state) {
case PIO_ST_IDLE:
break;
case PIO_ST_LAST:
- ata_pio_complete(ap);
+ qc_completed = ata_pio_complete(ap);
break;
case PIO_ST_POLL:
}
if (timeout)
- queue_delayed_work(ata_wq, &ap->pio_task,
- timeout);
- else
- queue_work(ata_wq, &ap->pio_task);
+ queue_delayed_work(ata_wq, &ap->pio_task, timeout);
+ else if (!qc_completed)
+ goto fsm_start;
}
static void atapi_request_sense(struct ata_port *ap, struct ata_device *dev,
ata_tf_init(ap, &qc->tf, dev->devno);
- if (dev->flags & ATA_DFLAG_LBA48)
- qc->tf.flags |= ATA_TFLAG_LBA48;
+ if (dev->flags & ATA_DFLAG_LBA) {
+ qc->tf.flags |= ATA_TFLAG_LBA;
+
+ if (dev->flags & ATA_DFLAG_LBA48)
+ qc->tf.flags |= ATA_TFLAG_LBA48;
+ }
}
return qc;
return 0;
}
+ /**
+ * ata_host_set_remove - PCI layer callback for device removal
+ * @host_set: ATA host set that was removed
+ *
+ * Unregister all objects associated with this host set. Free those
+ * objects.
+ *
+ * LOCKING:
+ * Inherited from calling layer (may sleep).
+ */
+
+
+ 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);
+ }
+
+ free_irq(host_set->irq, host_set);
+
+ for (i = 0; i < host_set->n_ports; i++) {
+ ap = host_set->ports[i];
+
+ ata_scsi_release(ap->host);
+
+ if ((ap->flags & ATA_FLAG_NO_LEGACY) == 0) {
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ if (ioaddr->cmd_addr == 0x1f0)
+ release_region(0x1f0, 8);
+ else if (ioaddr->cmd_addr == 0x170)
+ release_region(0x170, 8);
+ }
+
+ scsi_host_put(ap->host);
+ }
+
+ if (host_set->ops->host_stop)
+ host_set->ops->host_stop(host_set);
+
+ kfree(host_set);
+ }
+
/**
* ata_scsi_release - SCSI layer callback hook for host unload
* @host: libata host to be unloaded
{
struct device *dev = pci_dev_to_dev(pdev);
struct ata_host_set *host_set = dev_get_drvdata(dev);
- 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);
- }
-
- free_irq(host_set->irq, host_set);
-
- for (i = 0; i < host_set->n_ports; i++) {
- ap = host_set->ports[i];
-
- ata_scsi_release(ap->host);
-
- if ((ap->flags & ATA_FLAG_NO_LEGACY) == 0) {
- struct ata_ioports *ioaddr = &ap->ioaddr;
-
- if (ioaddr->cmd_addr == 0x1f0)
- release_region(0x1f0, 8);
- else if (ioaddr->cmd_addr == 0x170)
- release_region(0x170, 8);
- }
-
- scsi_host_put(ap->host);
- }
-
- if (host_set->ops->host_stop)
- host_set->ops->host_stop(host_set);
-
- kfree(host_set);
+ ata_host_set_remove(host_set);
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_host_set_remove);
EXPORT_SYMBOL_GPL(ata_sg_init);
EXPORT_SYMBOL_GPL(ata_sg_init_one);
EXPORT_SYMBOL_GPL(ata_qc_complete);