@@ -4228,7 +4228,7 @@ void ata_std_postreset(struct ata_link *link, unsigned int *classes)
* RETURNS:
* 1 if @dev matches @new_class and @new_id, 0 otherwise.
*/
-static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class,
+int ata_dev_same_device(struct ata_device *dev, unsigned int new_class,
const u16 *new_id)
{
const u16 *old_id = dev->id;
@@ -7391,3 +7391,4 @@ EXPORT_SYMBOL_GPL(ata_cable_80wire);
EXPORT_SYMBOL_GPL(ata_cable_unknown);
EXPORT_SYMBOL_GPL(ata_cable_ignore);
EXPORT_SYMBOL_GPL(ata_cable_sata);
+EXPORT_SYMBOL_GPL(ata_dev_same_device);
\ No newline at end of file
@@ -620,6 +620,22 @@ static int sas_get_ata_command_set(struct domain_device *dev)
return ata_dev_classify(&tf);
}
+static void sas_ata_store_id(struct domain_device *dev)
+{
+ struct ata_device *ata_dev = sas_to_ata_dev(dev);
+ unsigned char model[ATA_ID_PROD_LEN + 1];
+ unsigned char serial[ATA_ID_SERNO_LEN + 1];
+
+ /* store the ata device's class and id */
+ memcpy(dev->sata_dev.id, ata_dev->id, ATA_ID_WORDS);
+ dev->sata_dev.class = ata_dev->class;
+
+ ata_id_c_string(ata_dev->id, model, ATA_ID_PROD, sizeof(model));
+ ata_id_c_string(ata_dev->id, serial, ATA_ID_SERNO, sizeof(serial));
+
+ sas_ata_printk(KERN_INFO, dev, "model:%s serial:%s\n", model, serial);
+}
+
void sas_probe_sata(struct asd_sas_port *port)
{
struct domain_device *dev, *n;
@@ -644,6 +660,8 @@ void sas_probe_sata(struct asd_sas_port *port)
*/
if (ata_dev_disabled(sas_to_ata_dev(dev)))
sas_fail_probe(dev, __func__, -ENODEV);
+ else
+ sas_ata_store_id(dev);
}
}
@@ -2053,9 +2053,37 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id, bool last)
action = ", needs recovery";
SAS_DPRINTK("ex %016llx phy 0x%x broadcast flutter%s\n",
SAS_ADDR(dev->sas_addr), phy_id, action);
+
+ /* the phy attached address will be updated by sas_ex_phy_discover()
+ * and sometimes become abnormal
+ */
+ if (SAS_ADDR(phy->attached_sas_addr) != SAS_ADDR(sas_addr) ||
+ SAS_ADDR(phy->attached_sas_addr) == 0) {
+ /* if attached_sas_addr become abnormal, we must set the
+ * original address back so that the device can be unregistered
+ */
+ memcpy(phy->attached_sas_addr, sas_addr, SAS_ADDR_SIZE);
+ SAS_DPRINTK("phy address(%016llx) abnormal, origin:%016llx\n",
+ SAS_ADDR(phy->attached_sas_addr),
+ SAS_ADDR(sas_addr));
+ goto unregister;
+ }
+
+
+ if (ata_dev) {
+ struct ata_device *adev = sas_to_ata_dev(ata_dev);
+ unsigned int class = ata_dev->sata_dev.class;
+ u16 *id = ata_dev->sata_dev.id;
+
+ /* to see if the disk is replaced with another one */
+ if (!ata_dev_same_device(adev, class, id))
+ goto unregister;
+ }
+
return res;
}
+unregister:
/* we always have to delete the old device when we went here */
SAS_DPRINTK("ex %016llx phy 0x%x replace %016llx\n",
SAS_ADDR(dev->sas_addr), phy_id,
@@ -1140,6 +1140,8 @@ extern int sata_scr_write(struct ata_link *link, int reg, u32 val);
extern int sata_scr_write_flush(struct ata_link *link, int reg, u32 val);
extern bool ata_link_online(struct ata_link *link);
extern bool ata_link_offline(struct ata_link *link);
+extern int ata_dev_same_device(struct ata_device *dev, unsigned int new_class,
+ const u16 *new_id);
#ifdef CONFIG_PM
extern int ata_host_suspend(struct ata_host *host, pm_message_t mesg);
extern void ata_host_resume(struct ata_host *host);
@@ -164,6 +164,7 @@ struct sata_device {
struct ata_host ata_host;
struct smp_resp rps_resp ____cacheline_aligned; /* report_phy_sata_resp */
u8 fis[ATA_RESP_FIS_SIZE];
+ u16 id[ATA_ID_WORDS];
};
struct ssp_device {