/* * libata-acpi.c * Provides ACPI support for PATA/SATA. * * Copyright (C) 2006 Intel Corp. * Copyright (C) 2006 Randy Dunlap */ #include #include #include #include #include #include #include #include #include "libata.h" #include #include #include #include #include #include #include #define SATA_ROOT_PORT(x) (((x) >> 16) & 0xffff) #define SATA_PORT_NUMBER(x) ((x) & 0xffff) /* or NO_PORT_MULT */ #define NO_PORT_MULT 0xffff #define SATA_ADR_RSVD 0xffffffff #define REGS_PER_GTF 7 struct taskfile_array { u8 tfa[REGS_PER_GTF]; /* regs. 0x1f1 - 0x1f7 */ }; /* * Helper - belongs in the PCI layer somewhere eventually */ static int is_pci_dev(struct device *dev) { return (dev->bus == &pci_bus_type); } /** * sata_get_dev_handle - finds acpi_handle and PCI device.function * @dev: device to locate * @handle: returned acpi_handle for @dev * @pcidevfn: return PCI device.func for @dev * * This function is somewhat SATA-specific. Or at least the * PATA & SATA versions of this function are different, * so it's not entirely generic code. * * Returns 0 on success, <0 on error. */ static int sata_get_dev_handle(struct device *dev, acpi_handle *handle, acpi_integer *pcidevfn) { struct pci_dev *pci_dev; acpi_integer addr; if (!is_pci_dev(dev)) return -ENODEV; pci_dev = to_pci_dev(dev); /* NOTE: PCI-specific */ /* Please refer to the ACPI spec for the syntax of _ADR. */ addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn); *pcidevfn = addr; *handle = acpi_get_child(DEVICE_ACPI_HANDLE(dev->parent), addr); if (!*handle) return -ENODEV; return 0; } /** * pata_get_dev_handle - finds acpi_handle and PCI device.function * @dev: device to locate * @handle: returned acpi_handle for @dev * @pcidevfn: return PCI device.func for @dev * * The PATA and SATA versions of this function are different. * * Returns 0 on success, <0 on error. */ static int pata_get_dev_handle(struct device *dev, acpi_handle *handle, acpi_integer *pcidevfn) { unsigned int bus, devnum, func; acpi_integer addr; acpi_handle dev_handle, parent_handle; struct acpi_buffer buffer = {.length = ACPI_ALLOCATE_BUFFER, .pointer = NULL}; acpi_status status; struct acpi_device_info *dinfo = NULL; int ret = -ENODEV; struct pci_dev *pdev; if (!is_pci_dev(dev)) return -ENODEV; pdev = to_pci_dev(dev); bus = pdev->bus->number; devnum = PCI_SLOT(pdev->devfn); func = PCI_FUNC(pdev->devfn); dev_handle = DEVICE_ACPI_HANDLE(dev); parent_handle = DEVICE_ACPI_HANDLE(dev->parent); status = acpi_get_object_info(parent_handle, &buffer); if (ACPI_FAILURE(status)) goto err; dinfo = buffer.pointer; if (dinfo && (dinfo->valid & ACPI_VALID_ADR) && dinfo->address == bus) { /* ACPI spec for _ADR for PCI bus: */ addr = (acpi_integer)(devnum << 16 | func); *pcidevfn = addr; *handle = dev_handle; } else { goto err; } if (!*handle) goto err; ret = 0; err: kfree(dinfo); return ret; } struct walk_info { /* can be trimmed some */ struct device *dev; struct acpi_device *adev; acpi_handle handle; acpi_integer pcidevfn; unsigned int drivenum; acpi_handle obj_handle; struct ata_port *ataport; struct ata_device *atadev; u32 sata_adr; int status; char basepath[ACPI_PATHNAME_MAX]; int basepath_len; }; static acpi_status get_devices(acpi_handle handle, u32 level, void *context, void **return_value) { acpi_status status; struct walk_info *winfo = context; struct acpi_buffer namebuf = {ACPI_ALLOCATE_BUFFER, NULL}; char *pathname; struct acpi_buffer buffer; struct acpi_device_info *dinfo; status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &namebuf); if (status) goto ret; pathname = namebuf.pointer; buffer.length = ACPI_ALLOCATE_BUFFER; buffer.pointer = NULL; status = acpi_get_object_info(handle, &buffer); if (ACPI_FAILURE(status)) goto out2; dinfo = buffer.pointer; /* find full device path name for pcidevfn */ if (dinfo && (dinfo->valid & ACPI_VALID_ADR) && dinfo->address == winfo->pcidevfn) { if (ata_msg_probe(winfo->ataport)) ata_dev_printk(winfo->atadev, KERN_DEBUG, ":%s: matches pcidevfn (0x%llx)\n", pathname, winfo->pcidevfn); strlcpy(winfo->basepath, pathname, sizeof(winfo->basepath)); winfo->basepath_len = strlen(pathname); goto out; } /* if basepath is not yet known, ignore this object */ if (!winfo->basepath_len) goto out; /* if this object is in scope of basepath, maybe use it */ if (strncmp(pathname, winfo->basepath, winfo->basepath_len) == 0) { if (!(dinfo->valid & ACPI_VALID_ADR)) goto out; if (ata_msg_probe(winfo->ataport)) ata_dev_printk(winfo->atadev, KERN_DEBUG, "GOT ONE: (%s) root_port = 0x%llx," " port_num = 0x%llx\n", pathname, SATA_ROOT_PORT(dinfo->address), SATA_PORT_NUMBER(dinfo->address)); /* heuristics: */ if (SATA_PORT_NUMBER(dinfo->address) != NO_PORT_MULT) if (ata_msg_probe(winfo->ataport)) ata_dev_printk(winfo->atadev, KERN_DEBUG, "warning: don't" " know how to handle SATA port" " multiplier\n"); if (SATA_ROOT_PORT(dinfo->address) == winfo->ataport->port_no && SATA_PORT_NUMBER(dinfo->address) == NO_PORT_MULT) { if (ata_msg_probe(winfo->ataport)) ata_dev_printk(winfo->atadev, KERN_DEBUG, "THIS ^^^^^ is the requested" " SATA drive (handle = 0x%p)\n", handle); winfo->sata_adr = dinfo->address; winfo->obj_handle = handle; } } out: kfree(dinfo); out2: kfree(pathname); ret: return status; } /* Get the SATA drive _ADR object. */ static int get_sata_adr(struct device *dev, acpi_handle handle, acpi_integer pcidevfn, unsigned int drive, struct ata_port *ap, struct ata_device *atadev, u32 *dev_adr) { acpi_status status; struct walk_info *winfo; int err = -ENOMEM; winfo = kzalloc(sizeof(struct walk_info), GFP_KERNEL); if (!winfo) goto out; winfo->dev = dev; winfo->atadev = atadev; winfo->ataport = ap; if (acpi_bus_get_device(handle, &winfo->adev) < 0) if (ata_msg_probe(ap)) ata_dev_printk(winfo->atadev, KERN_DEBUG, "acpi_bus_get_device failed\n"); winfo->handle = handle; winfo->pcidevfn = pcidevfn; winfo->drivenum = drive; status = acpi_get_devices(NULL, get_devices, winfo, NULL); if (ACPI_FAILURE(status)) { if (ata_msg_probe(ap)) ata_dev_printk(winfo->atadev, KERN_DEBUG, "%s: acpi_get_devices failed\n", __FUNCTION__); err = -ENODEV; } else { *dev_adr = winfo->sata_adr; atadev->obj_handle = winfo->obj_handle; err = 0; } kfree(winfo); out: return err; } /** * do_drive_get_GTF - get the drive bootup default taskfile settings * @dev: target ATA device * @gtf_length: number of bytes of _GTF data returned at @gtf_address * @gtf_address: buffer containing _GTF taskfile arrays * * This applies to both PATA and SATA drives. * * The _GTF method has no input parameters. * It returns a variable number of register set values (registers * hex 1F1..1F7, taskfiles). * The is not known in advance, so have ACPI-CA * allocate the buffer as needed and return it, then free it later. * * The returned @gtf_length and @gtf_address are only valid if the * function return value is 0. */ static int do_drive_get_GTF(struct ata_device *dev, unsigned int *gtf_length, unsigned long *gtf_address, unsigned long *obj_loc) { struct ata_port *ap = dev->ap; acpi_status status; acpi_handle dev_handle = NULL; acpi_handle chan_handle, drive_handle; acpi_integer pcidevfn = 0; u32 dev_adr; struct acpi_buffer output; union acpi_object *out_obj; struct device *gdev = ap->host->dev; int err = -ENODEV; *gtf_length = 0; *gtf_address = 0UL; *obj_loc = 0UL; if (libata_noacpi) return 0; if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER: port#: %d\n", __FUNCTION__, ap->port_no); if (!ata_dev_enabled(dev) || (ap->flags & ATA_FLAG_DISABLED)) { if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: ERR: " "ata_dev_present: %d, PORT_DISABLED: %lu\n", __FUNCTION__, ata_dev_enabled(dev), ap->flags & ATA_FLAG_DISABLED); goto out; } /* Don't continue if device has no _ADR method. * _GTF is intended for known motherboard devices. */ if (!(ap->flags & ATA_FLAG_ACPI_SATA)) { err = pata_get_dev_handle(gdev, &dev_handle, &pcidevfn); if (err < 0) { if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: pata_get_dev_handle failed (%d)\n", __FUNCTION__, err); goto out; } } else { err = sata_get_dev_handle(gdev, &dev_handle, &pcidevfn); if (err < 0) { if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: sata_get_dev_handle failed (%d\n", __FUNCTION__, err); goto out; } } /* Get this drive's _ADR info. if not already known. */ if (!dev->obj_handle) { if (!(ap->flags & ATA_FLAG_ACPI_SATA)) { /* get child objects of dev_handle == channel objects, * + _their_ children == drive objects */ /* channel is ap->port_no */ chan_handle = acpi_get_child(dev_handle, ap->port_no); if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: chan adr=%d: chan_handle=0x%p\n", __FUNCTION__, ap->port_no, chan_handle); if (!chan_handle) { err = -ENODEV; goto out; } /* TBD: could also check ACPI object VALID bits */ drive_handle = acpi_get_child(chan_handle, dev->devno); if (!drive_handle) { err = -ENODEV; goto out; } dev_adr = dev->devno; dev->obj_handle = drive_handle; } else { /* for SATA mode */ dev_adr = SATA_ADR_RSVD; err = get_sata_adr(gdev, dev_handle, pcidevfn, 0, ap, dev, &dev_adr); } if (err < 0 || dev_adr == SATA_ADR_RSVD || !dev->obj_handle) { if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: get_sata/pata_adr failed: " "err=%d, dev_adr=%u, obj_handle=0x%p\n", __FUNCTION__, err, dev_adr, dev->obj_handle); goto out; } } /* Setting up output buffer */ output.length = ACPI_ALLOCATE_BUFFER; output.pointer = NULL; /* ACPI-CA sets this; save/free it later */ /* _GTF has no input parameters */ err = -EIO; status = acpi_evaluate_object(dev->obj_handle, "_GTF", NULL, &output); if (ACPI_FAILURE(status)) { if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: Run _GTF error: status = 0x%x\n", __FUNCTION__, status); goto out; } if (!output.length || !output.pointer) { if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: Run _GTF: " "length or ptr is NULL (0x%llx, 0x%p)\n", __FUNCTION__, (unsigned long long)output.length, output.pointer); kfree(output.pointer); goto out; } out_obj = output.pointer; if (out_obj->type != ACPI_TYPE_BUFFER) { kfree(output.pointer); if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: Run _GTF: " "error: expected object type of " " ACPI_TYPE_BUFFER, got 0x%x\n", __FUNCTION__, out_obj->type); err = -ENOENT; goto out; } if (!out_obj->buffer.length || !out_obj->buffer.pointer || out_obj->buffer.length % REGS_PER_GTF) { if (ata_msg_drv(ap)) ata_dev_printk(dev, KERN_ERR, "%s: unexpected GTF length (%d) or addr (0x%p)\n", __FUNCTION__, out_obj->buffer.length, out_obj->buffer.pointer); err = -ENOENT; goto out; } *gtf_length = out_obj->buffer.length; *gtf_address = (unsigned long)out_obj->buffer.pointer; *obj_loc = (unsigned long)out_obj; if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: returning " "gtf_length=%d, gtf_address=0x%lx, obj_loc=0x%lx\n", __FUNCTION__, *gtf_length, *gtf_address, *obj_loc); err = 0; out: return err; } /** * taskfile_load_raw - send taskfile registers to host controller * @dev: target ATA device * @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7) * * Outputs ATA taskfile to standard ATA host controller using MMIO * or PIO as indicated by the ATA_FLAG_MMIO flag. * Writes the control, feature, nsect, lbal, lbam, and lbah registers. * Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect, * hob_lbal, hob_lbam, and hob_lbah. * * This function waits for idle (!BUSY and !DRQ) after writing * registers. If the control register has a new value, this * function also waits for idle after writing control and before * writing the remaining registers. * * LOCKING: TBD: * Inherited from caller. */ static void taskfile_load_raw(struct ata_device *dev, const struct taskfile_array *gtf) { struct ata_port *ap = dev->ap; struct ata_taskfile tf; unsigned int err; if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: (0x1f1-1f7): hex: " "%02x %02x %02x %02x %02x %02x %02x\n", __FUNCTION__, gtf->tfa[0], gtf->tfa[1], gtf->tfa[2], gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]); if ((gtf->tfa[0] == 0) && (gtf->tfa[1] == 0) && (gtf->tfa[2] == 0) && (gtf->tfa[3] == 0) && (gtf->tfa[4] == 0) && (gtf->tfa[5] == 0) && (gtf->tfa[6] == 0)) return; ata_tf_init(dev, &tf); /* convert gtf to tf */ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; /* TBD */ tf.protocol = ATA_PROT_NODATA; tf.feature = gtf->tfa[0]; /* 0x1f1 */ tf.nsect = gtf->tfa[1]; /* 0x1f2 */ tf.lbal = gtf->tfa[2]; /* 0x1f3 */ tf.lbam = gtf->tfa[3]; /* 0x1f4 */ tf.lbah = gtf->tfa[4]; /* 0x1f5 */ tf.device = gtf->tfa[5]; /* 0x1f6 */ tf.command = gtf->tfa[6]; /* 0x1f7 */ err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); if (err && ata_msg_probe(ap)) ata_dev_printk(dev, KERN_ERR, "%s: ata_exec_internal failed: %u\n", __FUNCTION__, err); } /** * do_drive_set_taskfiles - write the drive taskfile settings from _GTF * @dev: target ATA device * @gtf_length: total number of bytes of _GTF taskfiles * @gtf_address: location of _GTF taskfile arrays * * This applies to both PATA and SATA drives. * * Write {gtf_address, length gtf_length} in groups of * REGS_PER_GTF bytes. */ static int do_drive_set_taskfiles(struct ata_device *dev, unsigned int gtf_length, unsigned long gtf_address) { struct ata_port *ap = dev->ap; int err = -ENODEV; int gtf_count = gtf_length / REGS_PER_GTF; int ix; struct taskfile_array *gtf; if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER: port#: %d\n", __FUNCTION__, ap->port_no); if (libata_noacpi || !(ap->flags & ATA_FLAG_ACPI_SATA)) return 0; if (!ata_dev_enabled(dev) || (ap->flags & ATA_FLAG_DISABLED)) goto out; if (!gtf_count) /* shouldn't be here */ goto out; if (gtf_length % REGS_PER_GTF) { if (ata_msg_drv(ap)) ata_dev_printk(dev, KERN_ERR, "%s: unexpected GTF length (%d)\n", __FUNCTION__, gtf_length); goto out; } for (ix = 0; ix < gtf_count; ix++) { gtf = (struct taskfile_array *) (gtf_address + ix * REGS_PER_GTF); /* send all TaskFile registers (0x1f1-0x1f7) *in*that*order* */ taskfile_load_raw(dev, gtf); } err = 0; out: return err; } /** * ata_acpi_exec_tfs - get then write drive taskfile settings * @ap: the ata_port for the drive * * This applies to both PATA and SATA drives. */ int ata_acpi_exec_tfs(struct ata_port *ap) { int ix; int ret = 0; unsigned int gtf_length; unsigned long gtf_address; unsigned long obj_loc; if (libata_noacpi) return 0; /* * TBD - implement PATA support. For now, * we should not run GTF on PATA devices since some * PATA require execution of GTM/STM before GTF. */ if (!(ap->flags & ATA_FLAG_ACPI_SATA)) return 0; for (ix = 0; ix < ATA_MAX_DEVICES; ix++) { struct ata_device *dev = &ap->device[ix]; if (!ata_dev_enabled(dev)) continue; ret = do_drive_get_GTF(dev, >f_length, >f_address, &obj_loc); if (ret < 0) { if (ata_msg_probe(ap)) ata_port_printk(ap, KERN_DEBUG, "%s: get_GTF error (%d)\n", __FUNCTION__, ret); break; } ret = do_drive_set_taskfiles(dev, gtf_length, gtf_address); kfree((void *)obj_loc); if (ret < 0) { if (ata_msg_probe(ap)) ata_port_printk(ap, KERN_DEBUG, "%s: set_taskfiles error (%d)\n", __FUNCTION__, ret); break; } } return ret; } /** * ata_acpi_push_id - send Identify data to drive * @dev: target ATA device * * _SDD ACPI object: for SATA mode only * Must be after Identify (Packet) Device -- uses its data * ATM this function never returns a failure. It is an optional * method and if it fails for whatever reason, we should still * just keep going. */ int ata_acpi_push_id(struct ata_device *dev) { struct ata_port *ap = dev->ap; acpi_handle handle; acpi_integer pcidevfn; int err; struct device *gdev = ap->host->dev; u32 dev_adr; acpi_status status; struct acpi_object_list input; union acpi_object in_params[1]; if (libata_noacpi) return 0; if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: ix = %d, port#: %d\n", __FUNCTION__, dev->devno, ap->port_no); /* Don't continue if not a SATA device. */ if (!(ap->flags & ATA_FLAG_ACPI_SATA)) { if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: Not a SATA device\n", __FUNCTION__); goto out; } /* Don't continue if device has no _ADR method. * _SDD is intended for known motherboard devices. */ err = sata_get_dev_handle(gdev, &handle, &pcidevfn); if (err < 0) { if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: sata_get_dev_handle failed (%d\n", __FUNCTION__, err); goto out; } /* Get this drive's _ADR info, if not already known */ if (!dev->obj_handle) { dev_adr = SATA_ADR_RSVD; err = get_sata_adr(gdev, handle, pcidevfn, dev->devno, ap, dev, &dev_adr); if (err < 0 || dev_adr == SATA_ADR_RSVD || !dev->obj_handle) { if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: get_sata_adr failed: " "err=%d, dev_adr=%u, obj_handle=0x%p\n", __FUNCTION__, err, dev_adr, dev->obj_handle); goto out; } } /* Give the drive Identify data to the drive via the _SDD method */ /* _SDD: set up input parameters */ input.count = 1; input.pointer = in_params; in_params[0].type = ACPI_TYPE_BUFFER; in_params[0].buffer.length = sizeof(dev->id[0]) * ATA_ID_WORDS; in_params[0].buffer.pointer = (u8 *)dev->id; /* Output buffer: _SDD has no output */ /* It's OK for _SDD to be missing too. */ swap_buf_le16(dev->id, ATA_ID_WORDS); status = acpi_evaluate_object(dev->obj_handle, "_SDD", &input, NULL); swap_buf_le16(dev->id, ATA_ID_WORDS); err = ACPI_FAILURE(status) ? -EIO : 0; if (err < 0) { if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s _SDD error: status = 0x%x\n", __FUNCTION__, status); } /* always return success */ out: return 0; }