diff options
author | Jeff Garzik <jeff@garzik.org> | 2006-03-29 19:59:39 -0500 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-03-29 19:59:39 -0500 |
commit | 4f0e7c51ae392d841be395a9c6b8d26a9fbf33d2 (patch) | |
tree | 664564736e52a88e14d9c699c5c723b89785f4cb /drivers/scsi | |
parent | 74d89c16735d83349ea74232031819e989a49156 (diff) | |
parent | 55d8ca4f8094246da6e71889a4e04bfafaa78b10 (diff) |
Merge branch 'upstream'
Conflicts:
drivers/scsi/sata_mv.c
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/libata-bmdma.c | 26 | ||||
-rw-r--r-- | drivers/scsi/libata-core.c | 57 | ||||
-rw-r--r-- | drivers/scsi/sata_mv.c | 39 |
3 files changed, 90 insertions, 32 deletions
diff --git a/drivers/scsi/libata-bmdma.c b/drivers/scsi/libata-bmdma.c index 95d81d86d8b7..835dff0bafdc 100644 --- a/drivers/scsi/libata-bmdma.c +++ b/drivers/scsi/libata-bmdma.c | |||
@@ -703,6 +703,7 @@ ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int | |||
703 | struct ata_probe_ent *probe_ent = | 703 | struct ata_probe_ent *probe_ent = |
704 | ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]); | 704 | ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]); |
705 | int p = 0; | 705 | int p = 0; |
706 | unsigned long bmdma; | ||
706 | 707 | ||
707 | if (!probe_ent) | 708 | if (!probe_ent) |
708 | return NULL; | 709 | return NULL; |
@@ -716,7 +717,12 @@ ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int | |||
716 | probe_ent->port[p].altstatus_addr = | 717 | probe_ent->port[p].altstatus_addr = |
717 | probe_ent->port[p].ctl_addr = | 718 | probe_ent->port[p].ctl_addr = |
718 | pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; | 719 | pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; |
719 | probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4); | 720 | bmdma = pci_resource_start(pdev, 4); |
721 | if (bmdma) { | ||
722 | if (inb(bmdma + 2) & 0x80) | ||
723 | probe_ent->host_set_flags |= ATA_HOST_SIMPLEX; | ||
724 | probe_ent->port[p].bmdma_addr = bmdma; | ||
725 | } | ||
720 | ata_std_ports(&probe_ent->port[p]); | 726 | ata_std_ports(&probe_ent->port[p]); |
721 | p++; | 727 | p++; |
722 | } | 728 | } |
@@ -726,7 +732,13 @@ ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int | |||
726 | probe_ent->port[p].altstatus_addr = | 732 | probe_ent->port[p].altstatus_addr = |
727 | probe_ent->port[p].ctl_addr = | 733 | probe_ent->port[p].ctl_addr = |
728 | pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; | 734 | pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; |
729 | probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4) + 8; | 735 | bmdma = pci_resource_start(pdev, 4); |
736 | if (bmdma) { | ||
737 | bmdma += 8; | ||
738 | if(inb(bmdma + 2) & 0x80) | ||
739 | probe_ent->host_set_flags |= ATA_HOST_SIMPLEX; | ||
740 | probe_ent->port[p].bmdma_addr = bmdma; | ||
741 | } | ||
730 | ata_std_ports(&probe_ent->port[p]); | 742 | ata_std_ports(&probe_ent->port[p]); |
731 | p++; | 743 | p++; |
732 | } | 744 | } |
@@ -740,6 +752,7 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev, | |||
740 | struct ata_port_info *port, int port_num) | 752 | struct ata_port_info *port, int port_num) |
741 | { | 753 | { |
742 | struct ata_probe_ent *probe_ent; | 754 | struct ata_probe_ent *probe_ent; |
755 | unsigned long bmdma; | ||
743 | 756 | ||
744 | probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port); | 757 | probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port); |
745 | if (!probe_ent) | 758 | if (!probe_ent) |
@@ -766,8 +779,13 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev, | |||
766 | break; | 779 | break; |
767 | } | 780 | } |
768 | 781 | ||
769 | probe_ent->port[0].bmdma_addr = | 782 | bmdma = pci_resource_start(pdev, 4); |
770 | pci_resource_start(pdev, 4) + 8 * port_num; | 783 | if (bmdma != 0) { |
784 | bmdma += 8 * port_num; | ||
785 | probe_ent->port[0].bmdma_addr = bmdma; | ||
786 | if (inb(bmdma + 2) & 0x80) | ||
787 | probe_ent->host_set_flags |= ATA_HOST_SIMPLEX; | ||
788 | } | ||
771 | ata_std_ports(&probe_ent->port[0]); | 789 | ata_std_ports(&probe_ent->port[0]); |
772 | 790 | ||
773 | return probe_ent; | 791 | return probe_ent; |
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 83c92b19e7f4..a14187e32d0a 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c | |||
@@ -62,7 +62,9 @@ | |||
62 | #include "libata.h" | 62 | #include "libata.h" |
63 | 63 | ||
64 | static unsigned int ata_dev_init_params(struct ata_port *ap, | 64 | static unsigned int ata_dev_init_params(struct ata_port *ap, |
65 | struct ata_device *dev); | 65 | struct ata_device *dev, |
66 | u16 heads, | ||
67 | u16 sectors); | ||
66 | static void ata_set_mode(struct ata_port *ap); | 68 | static void ata_set_mode(struct ata_port *ap); |
67 | static unsigned int ata_dev_set_xfermode(struct ata_port *ap, | 69 | static unsigned int ata_dev_set_xfermode(struct ata_port *ap, |
68 | struct ata_device *dev); | 70 | struct ata_device *dev); |
@@ -1140,7 +1142,7 @@ static int ata_dev_read_id(struct ata_port *ap, struct ata_device *dev, | |||
1140 | swap_buf_le16(id, ATA_ID_WORDS); | 1142 | swap_buf_le16(id, ATA_ID_WORDS); |
1141 | 1143 | ||
1142 | /* sanity check */ | 1144 | /* sanity check */ |
1143 | if ((class == ATA_DEV_ATA) != ata_id_is_ata(id)) { | 1145 | if ((class == ATA_DEV_ATA) != (ata_id_is_ata(id) | ata_id_is_cfa(id))) { |
1144 | rc = -EINVAL; | 1146 | rc = -EINVAL; |
1145 | reason = "device reports illegal type"; | 1147 | reason = "device reports illegal type"; |
1146 | goto err_out; | 1148 | goto err_out; |
@@ -1156,7 +1158,7 @@ static int ata_dev_read_id(struct ata_port *ap, struct ata_device *dev, | |||
1156 | * Some drives were very specific about that exact sequence. | 1158 | * Some drives were very specific about that exact sequence. |
1157 | */ | 1159 | */ |
1158 | if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) { | 1160 | if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) { |
1159 | err_mask = ata_dev_init_params(ap, dev); | 1161 | err_mask = ata_dev_init_params(ap, dev, id[3], id[6]); |
1160 | if (err_mask) { | 1162 | if (err_mask) { |
1161 | rc = -EIO; | 1163 | rc = -EIO; |
1162 | reason = "INIT_DEV_PARAMS failed"; | 1164 | reason = "INIT_DEV_PARAMS failed"; |
@@ -1418,7 +1420,11 @@ static int ata_bus_probe(struct ata_port *ap) | |||
1418 | if (!found) | 1420 | if (!found) |
1419 | goto err_out_disable; | 1421 | goto err_out_disable; |
1420 | 1422 | ||
1421 | ata_set_mode(ap); | 1423 | if (ap->ops->set_mode) |
1424 | ap->ops->set_mode(ap); | ||
1425 | else | ||
1426 | ata_set_mode(ap); | ||
1427 | |||
1422 | if (ap->flags & ATA_FLAG_PORT_DISABLED) | 1428 | if (ap->flags & ATA_FLAG_PORT_DISABLED) |
1423 | goto err_out_disable; | 1429 | goto err_out_disable; |
1424 | 1430 | ||
@@ -1823,7 +1829,7 @@ static void ata_host_set_dma(struct ata_port *ap) | |||
1823 | */ | 1829 | */ |
1824 | static void ata_set_mode(struct ata_port *ap) | 1830 | static void ata_set_mode(struct ata_port *ap) |
1825 | { | 1831 | { |
1826 | int i, rc; | 1832 | int i, rc, used_dma = 0; |
1827 | 1833 | ||
1828 | /* step 1: calculate xfer_mask */ | 1834 | /* step 1: calculate xfer_mask */ |
1829 | for (i = 0; i < ATA_MAX_DEVICES; i++) { | 1835 | for (i = 0; i < ATA_MAX_DEVICES; i++) { |
@@ -1841,6 +1847,9 @@ static void ata_set_mode(struct ata_port *ap) | |||
1841 | dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask); | 1847 | dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask); |
1842 | dev->pio_mode = ata_xfer_mask2mode(pio_mask); | 1848 | dev->pio_mode = ata_xfer_mask2mode(pio_mask); |
1843 | dev->dma_mode = ata_xfer_mask2mode(dma_mask); | 1849 | dev->dma_mode = ata_xfer_mask2mode(dma_mask); |
1850 | |||
1851 | if (dev->dma_mode) | ||
1852 | used_dma = 1; | ||
1844 | } | 1853 | } |
1845 | 1854 | ||
1846 | /* step 2: always set host PIO timings */ | 1855 | /* step 2: always set host PIO timings */ |
@@ -1862,6 +1871,17 @@ static void ata_set_mode(struct ata_port *ap) | |||
1862 | goto err_out; | 1871 | goto err_out; |
1863 | } | 1872 | } |
1864 | 1873 | ||
1874 | /* | ||
1875 | * Record simplex status. If we selected DMA then the other | ||
1876 | * host channels are not permitted to do so. | ||
1877 | */ | ||
1878 | |||
1879 | if (used_dma && (ap->host_set->flags & ATA_HOST_SIMPLEX)) | ||
1880 | ap->host_set->simplex_claimed = 1; | ||
1881 | |||
1882 | /* | ||
1883 | * Chip specific finalisation | ||
1884 | */ | ||
1865 | if (ap->ops->post_set_mode) | 1885 | if (ap->ops->post_set_mode) |
1866 | ap->ops->post_set_mode(ap); | 1886 | ap->ops->post_set_mode(ap); |
1867 | 1887 | ||
@@ -2151,9 +2171,9 @@ static int sata_phy_resume(struct ata_port *ap) | |||
2151 | * so makes reset sequence different from the original | 2171 | * so makes reset sequence different from the original |
2152 | * ->phy_reset implementation and Jeff nervous. :-P | 2172 | * ->phy_reset implementation and Jeff nervous. :-P |
2153 | */ | 2173 | */ |
2154 | extern void ata_std_probeinit(struct ata_port *ap) | 2174 | void ata_std_probeinit(struct ata_port *ap) |
2155 | { | 2175 | { |
2156 | if (ap->flags & ATA_FLAG_SATA && ap->ops->scr_read) { | 2176 | if ((ap->flags & ATA_FLAG_SATA) && ap->ops->scr_read) { |
2157 | sata_phy_resume(ap); | 2177 | sata_phy_resume(ap); |
2158 | if (sata_dev_present(ap)) | 2178 | if (sata_dev_present(ap)) |
2159 | ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); | 2179 | ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); |
@@ -2651,13 +2671,14 @@ static int ata_dma_blacklisted(const struct ata_device *dev) | |||
2651 | */ | 2671 | */ |
2652 | static void ata_dev_xfermask(struct ata_port *ap, struct ata_device *dev) | 2672 | static void ata_dev_xfermask(struct ata_port *ap, struct ata_device *dev) |
2653 | { | 2673 | { |
2674 | struct ata_host_set *hs = ap->host_set; | ||
2654 | unsigned long xfer_mask; | 2675 | unsigned long xfer_mask; |
2655 | int i; | 2676 | int i; |
2656 | 2677 | ||
2657 | xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask, | 2678 | xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask, |
2658 | ap->udma_mask); | 2679 | ap->udma_mask); |
2659 | 2680 | ||
2660 | /* use port-wide xfermask for now */ | 2681 | /* FIXME: Use port-wide xfermask for now */ |
2661 | for (i = 0; i < ATA_MAX_DEVICES; i++) { | 2682 | for (i = 0; i < ATA_MAX_DEVICES; i++) { |
2662 | struct ata_device *d = &ap->device[i]; | 2683 | struct ata_device *d = &ap->device[i]; |
2663 | if (!ata_dev_present(d)) | 2684 | if (!ata_dev_present(d)) |
@@ -2667,12 +2688,23 @@ static void ata_dev_xfermask(struct ata_port *ap, struct ata_device *dev) | |||
2667 | xfer_mask &= ata_id_xfermask(d->id); | 2688 | xfer_mask &= ata_id_xfermask(d->id); |
2668 | if (ata_dma_blacklisted(d)) | 2689 | if (ata_dma_blacklisted(d)) |
2669 | xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA); | 2690 | xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA); |
2691 | /* Apply cable rule here. Don't apply it early because when | ||
2692 | we handle hot plug the cable type can itself change */ | ||
2693 | if (ap->cbl == ATA_CBL_PATA40) | ||
2694 | xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA); | ||
2670 | } | 2695 | } |
2671 | 2696 | ||
2672 | if (ata_dma_blacklisted(dev)) | 2697 | if (ata_dma_blacklisted(dev)) |
2673 | printk(KERN_WARNING "ata%u: dev %u is on DMA blacklist, " | 2698 | printk(KERN_WARNING "ata%u: dev %u is on DMA blacklist, " |
2674 | "disabling DMA\n", ap->id, dev->devno); | 2699 | "disabling DMA\n", ap->id, dev->devno); |
2675 | 2700 | ||
2701 | if (hs->flags & ATA_HOST_SIMPLEX) { | ||
2702 | if (hs->simplex_claimed) | ||
2703 | xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA); | ||
2704 | } | ||
2705 | if (ap->ops->mode_filter) | ||
2706 | xfer_mask = ap->ops->mode_filter(ap, dev, xfer_mask); | ||
2707 | |||
2676 | ata_unpack_xfermask(xfer_mask, &dev->pio_mask, &dev->mwdma_mask, | 2708 | ata_unpack_xfermask(xfer_mask, &dev->pio_mask, &dev->mwdma_mask, |
2677 | &dev->udma_mask); | 2709 | &dev->udma_mask); |
2678 | } | 2710 | } |
@@ -2727,16 +2759,16 @@ static unsigned int ata_dev_set_xfermode(struct ata_port *ap, | |||
2727 | */ | 2759 | */ |
2728 | 2760 | ||
2729 | static unsigned int ata_dev_init_params(struct ata_port *ap, | 2761 | static unsigned int ata_dev_init_params(struct ata_port *ap, |
2730 | struct ata_device *dev) | 2762 | struct ata_device *dev, |
2763 | u16 heads, | ||
2764 | u16 sectors) | ||
2731 | { | 2765 | { |
2732 | struct ata_taskfile tf; | 2766 | struct ata_taskfile tf; |
2733 | unsigned int err_mask; | 2767 | unsigned int err_mask; |
2734 | u16 sectors = dev->id[6]; | ||
2735 | u16 heads = dev->id[3]; | ||
2736 | 2768 | ||
2737 | /* Number of sectors per track 1-255. Number of heads 1-16 */ | 2769 | /* Number of sectors per track 1-255. Number of heads 1-16 */ |
2738 | if (sectors < 1 || sectors > 255 || heads < 1 || heads > 16) | 2770 | if (sectors < 1 || sectors > 255 || heads < 1 || heads > 16) |
2739 | return 0; | 2771 | return AC_ERR_INVALID; |
2740 | 2772 | ||
2741 | /* set up init dev params taskfile */ | 2773 | /* set up init dev params taskfile */ |
2742 | DPRINTK("init dev params \n"); | 2774 | DPRINTK("init dev params \n"); |
@@ -4678,6 +4710,7 @@ int ata_device_add(const struct ata_probe_ent *ent) | |||
4678 | host_set->mmio_base = ent->mmio_base; | 4710 | host_set->mmio_base = ent->mmio_base; |
4679 | host_set->private_data = ent->private_data; | 4711 | host_set->private_data = ent->private_data; |
4680 | host_set->ops = ent->port_ops; | 4712 | host_set->ops = ent->port_ops; |
4713 | host_set->flags = ent->host_set_flags; | ||
4681 | 4714 | ||
4682 | /* register each port bound to this device */ | 4715 | /* register each port bound to this device */ |
4683 | for (i = 0; i < ent->n_ports; i++) { | 4716 | for (i = 0; i < ent->n_ports; i++) { |
diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index 2819a75c4a84..4d965601efcf 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c | |||
@@ -1010,7 +1010,7 @@ static void mv_fill_sg(struct ata_queued_cmd *qc) | |||
1010 | 1010 | ||
1011 | pp->sg_tbl[i].addr = cpu_to_le32(addr & 0xffffffff); | 1011 | pp->sg_tbl[i].addr = cpu_to_le32(addr & 0xffffffff); |
1012 | pp->sg_tbl[i].addr_hi = cpu_to_le32((addr >> 16) >> 16); | 1012 | pp->sg_tbl[i].addr_hi = cpu_to_le32((addr >> 16) >> 16); |
1013 | pp->sg_tbl[i].flags_size = cpu_to_le32(len); | 1013 | pp->sg_tbl[i].flags_size = cpu_to_le32(len & 0xffff); |
1014 | 1014 | ||
1015 | sg_len -= len; | 1015 | sg_len -= len; |
1016 | addr += len; | 1016 | addr += len; |
@@ -1350,7 +1350,6 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant, | |||
1350 | { | 1350 | { |
1351 | void __iomem *mmio = host_set->mmio_base; | 1351 | void __iomem *mmio = host_set->mmio_base; |
1352 | void __iomem *hc_mmio = mv_hc_base(mmio, hc); | 1352 | void __iomem *hc_mmio = mv_hc_base(mmio, hc); |
1353 | struct ata_port *ap; | ||
1354 | struct ata_queued_cmd *qc; | 1353 | struct ata_queued_cmd *qc; |
1355 | u32 hc_irq_cause; | 1354 | u32 hc_irq_cause; |
1356 | int shift, port, port0, hard_port, handled; | 1355 | int shift, port, port0, hard_port, handled; |
@@ -1373,21 +1372,29 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant, | |||
1373 | 1372 | ||
1374 | for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) { | 1373 | for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) { |
1375 | u8 ata_status = 0; | 1374 | u8 ata_status = 0; |
1376 | ap = host_set->ports[port]; | 1375 | struct ata_port *ap = host_set->ports[port]; |
1376 | struct mv_port_priv *pp = ap->private_data; | ||
1377 | |||
1377 | hard_port = port & MV_PORT_MASK; /* range 0-3 */ | 1378 | hard_port = port & MV_PORT_MASK; /* range 0-3 */ |
1378 | handled = 0; /* ensure ata_status is set if handled++ */ | 1379 | handled = 0; /* ensure ata_status is set if handled++ */ |
1379 | 1380 | ||
1380 | if ((CRPB_DMA_DONE << hard_port) & hc_irq_cause) { | 1381 | /* Note that DEV_IRQ might happen spuriously during EDMA, |
1381 | /* new CRPB on the queue; just one at a time until NCQ | 1382 | * and should be ignored in such cases. We could mask it, |
1382 | */ | 1383 | * but it's pretty rare and may not be worth the overhead. |
1383 | ata_status = mv_get_crpb_status(ap); | 1384 | */ |
1384 | handled++; | 1385 | if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) { |
1385 | } else if ((DEV_IRQ << hard_port) & hc_irq_cause) { | 1386 | /* EDMA: check for response queue interrupt */ |
1386 | /* received ATA IRQ; read the status reg to clear INTRQ | 1387 | if ((CRPB_DMA_DONE << hard_port) & hc_irq_cause) { |
1387 | */ | 1388 | ata_status = mv_get_crpb_status(ap); |
1388 | ata_status = readb((void __iomem *) | 1389 | handled = 1; |
1390 | } | ||
1391 | } else { | ||
1392 | /* PIO: check for device (drive) interrupt */ | ||
1393 | if ((DEV_IRQ << hard_port) & hc_irq_cause) { | ||
1394 | ata_status = readb((void __iomem *) | ||
1389 | ap->ioaddr.status_addr); | 1395 | ap->ioaddr.status_addr); |
1390 | handled++; | 1396 | handled = 1; |
1397 | } | ||
1391 | } | 1398 | } |
1392 | 1399 | ||
1393 | if (ap && (ap->flags & ATA_FLAG_PORT_DISABLED)) | 1400 | if (ap && (ap->flags & ATA_FLAG_PORT_DISABLED)) |
@@ -1402,12 +1409,12 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant, | |||
1402 | if ((PORT0_ERR << shift) & relevant) { | 1409 | if ((PORT0_ERR << shift) & relevant) { |
1403 | mv_err_intr(ap); | 1410 | mv_err_intr(ap); |
1404 | err_mask |= AC_ERR_OTHER; | 1411 | err_mask |= AC_ERR_OTHER; |
1405 | handled++; | 1412 | handled = 1; |
1406 | } | 1413 | } |
1407 | 1414 | ||
1408 | if (handled && ap) { | 1415 | if (handled) { |
1409 | qc = ata_qc_from_tag(ap, ap->active_tag); | 1416 | qc = ata_qc_from_tag(ap, ap->active_tag); |
1410 | if (NULL != qc) { | 1417 | if (qc && (qc->flags & ATA_QCFLAG_ACTIVE)) { |
1411 | VPRINTK("port %u IRQ found for qc, " | 1418 | VPRINTK("port %u IRQ found for qc, " |
1412 | "ata_status 0x%x\n", port,ata_status); | 1419 | "ata_status 0x%x\n", port,ata_status); |
1413 | /* mark qc status appropriately */ | 1420 | /* mark qc status appropriately */ |