static int pm8001_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags, int is_tmf, struct pm8001_tmf_task *tmf) { struct domain_device *dev = task->dev; struct pm8001_hba_info *pm8001_ha; struct pm8001_device *pm8001_dev; struct pm8001_port *port = NULL; struct sas_task *t = task; struct pm8001_ccb_info *ccb; u32 tag = 0xdeadbeef, rc, n_elem = 0; u32 n = num; unsigned long flags = 0, flags_libsas = 0; if (!dev->port) { struct task_status_struct *tsm = &t->task_status; tsm->resp = SAS_TASK_UNDELIVERED; tsm->stat = SAS_PHY_DOWN; if (dev->dev_type != SATA_DEV) t->task_done(t); return 0; } pm8001_ha = pm8001_find_ha_by_dev(task->dev); PM8001_IO_DBG(pm8001_ha, pm8001_printk("pm8001_task_exec device \n ")); spin_lock_irqsave(&pm8001_ha->lock, flags); do { dev = t->dev; pm8001_dev = dev->lldd_dev; if (DEV_IS_GONE(pm8001_dev)) { if (pm8001_dev) { PM8001_IO_DBG(pm8001_ha, pm8001_printk("device %d not ready.\n", pm8001_dev->device_id)); } else { PM8001_IO_DBG(pm8001_ha, pm8001_printk("device %016llx not " "ready.\n", SAS_ADDR(dev->sas_addr))); } rc = SAS_PHY_DOWN; goto out_done; } port = &pm8001_ha->port[sas_find_local_port_id(dev)]; if (!port->port_attached) { if (sas_protocol_ata(t->task_proto)) { struct task_status_struct *ts = &t->task_status; ts->resp = SAS_TASK_UNDELIVERED; ts->stat = SAS_PHY_DOWN; spin_unlock_irqrestore(&pm8001_ha->lock, flags); spin_unlock_irqrestore(dev->sata_dev.ap->lock, flags_libsas); t->task_done(t); spin_lock_irqsave(dev->sata_dev.ap->lock, flags_libsas); spin_lock_irqsave(&pm8001_ha->lock, flags); if (n > 1) t = list_entry(t->list.next, struct sas_task, list); continue; } else { struct task_status_struct *ts = &t->task_status; ts->resp = SAS_TASK_UNDELIVERED; ts->stat = SAS_PHY_DOWN; t->task_done(t); if (n > 1) t = list_entry(t->list.next, struct sas_task, list); continue; } } rc = pm8001_tag_alloc(pm8001_ha, &tag); if (rc) goto err_out; ccb = &pm8001_ha->ccb_info[tag]; if (!sas_protocol_ata(t->task_proto)) { if (t->num_scatter) { n_elem = dma_map_sg(pm8001_ha->dev, t->scatter, t->num_scatter, t->data_dir); if (!n_elem) { rc = -ENOMEM; goto err_out_tag; } } } else { n_elem = t->num_scatter; } t->lldd_task = ccb; ccb->n_elem = n_elem; ccb->ccb_tag = tag; ccb->task = t; switch (t->task_proto) { case SAS_PROTOCOL_SMP: rc = pm8001_task_prep_smp(pm8001_ha, ccb); break; case SAS_PROTOCOL_SSP: if (is_tmf) rc = pm8001_task_prep_ssp_tm(pm8001_ha, ccb, tmf); else rc = pm8001_task_prep_ssp(pm8001_ha, ccb); break; case SAS_PROTOCOL_SATA: case SAS_PROTOCOL_STP: case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: rc = pm8001_task_prep_ata(pm8001_ha, ccb); break; default: dev_printk(KERN_ERR, pm8001_ha->dev, "unknown sas_task proto: 0x%x\n", t->task_proto); rc = -EINVAL; break; } if (rc) { PM8001_IO_DBG(pm8001_ha, pm8001_printk("rc is %x\n", rc)); goto err_out_tag; } /* TODO: select normal or high priority */ spin_lock(&t->task_state_lock); t->task_state_flags |= SAS_TASK_AT_INITIATOR; spin_unlock(&t->task_state_lock); pm8001_dev->running_req++; if (n > 1) t = list_entry(t->list.next, struct sas_task, list); } while (--n);
ssize_t pm80xx_get_fatal_dump(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; void __iomem *fatal_table_address = pm8001_ha->fatal_tbl_addr; u32 accum_len , reg_val, index, *temp; unsigned long start; u8 *direct_data; char *fatal_error_data = buf; pm8001_ha->forensic_info.data_buf.direct_data = buf; if (pm8001_ha->chip_id == chip_8001) { pm8001_ha->forensic_info.data_buf.direct_data += sprintf(pm8001_ha->forensic_info.data_buf.direct_data, "Not supported for SPC controller"); return (char *)pm8001_ha->forensic_info.data_buf.direct_data - (char *)buf; } if (pm8001_ha->forensic_info.data_buf.direct_offset == 0) { PM8001_IO_DBG(pm8001_ha, pm8001_printk("forensic_info TYPE_NON_FATAL..............\n")); direct_data = (u8 *)fatal_error_data; pm8001_ha->forensic_info.data_type = TYPE_NON_FATAL; pm8001_ha->forensic_info.data_buf.direct_len = SYSFS_OFFSET; pm8001_ha->forensic_info.data_buf.read_len = 0; pm8001_ha->forensic_info.data_buf.direct_data = direct_data; /* start to get data */ /* Program the MEMBASE II Shifting Register with 0x00.*/ pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER, pm8001_ha->fatal_forensic_shift_offset); pm8001_ha->forensic_last_offset = 0; pm8001_ha->forensic_fatal_step = 0; pm8001_ha->fatal_bar_loc = 0; } /* Read until accum_len is retrived */ accum_len = pm8001_mr32(fatal_table_address, MPI_FATAL_EDUMP_TABLE_ACCUM_LEN); PM8001_IO_DBG(pm8001_ha, pm8001_printk("accum_len 0x%x\n", accum_len)); if (accum_len == 0xFFFFFFFF) { PM8001_IO_DBG(pm8001_ha, pm8001_printk("Possible PCI issue 0x%x not expected\n", accum_len)); return -EIO; } if (accum_len == 0 || accum_len >= 0x100000) { pm8001_ha->forensic_info.data_buf.direct_data += sprintf(pm8001_ha->forensic_info.data_buf.direct_data, "%08x ", 0xFFFFFFFF); return (char *)pm8001_ha->forensic_info.data_buf.direct_data - (char *)buf; } temp = (u32 *)pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr; if (pm8001_ha->forensic_fatal_step == 0) { moreData: if (pm8001_ha->forensic_info.data_buf.direct_data) { /* Data is in bar, copy to host memory */ pm80xx_pci_mem_copy(pm8001_ha, pm8001_ha->fatal_bar_loc, pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr, pm8001_ha->forensic_info.data_buf.direct_len , 1); } pm8001_ha->fatal_bar_loc += pm8001_ha->forensic_info.data_buf.direct_len; pm8001_ha->forensic_info.data_buf.direct_offset += pm8001_ha->forensic_info.data_buf.direct_len; pm8001_ha->forensic_last_offset += pm8001_ha->forensic_info.data_buf.direct_len; pm8001_ha->forensic_info.data_buf.read_len = pm8001_ha->forensic_info.data_buf.direct_len; if (pm8001_ha->forensic_last_offset >= accum_len) { pm8001_ha->forensic_info.data_buf.direct_data += sprintf(pm8001_ha->forensic_info.data_buf.direct_data, "%08x ", 3); for (index = 0; index < (SYSFS_OFFSET / 4); index++) { pm8001_ha->forensic_info.data_buf.direct_data += sprintf(pm8001_ha-> forensic_info.data_buf.direct_data, "%08x ", *(temp + index)); } pm8001_ha->fatal_bar_loc = 0; pm8001_ha->forensic_fatal_step = 1; pm8001_ha->fatal_forensic_shift_offset = 0; pm8001_ha->forensic_last_offset = 0; return (char *)pm8001_ha-> forensic_info.data_buf.direct_data - (char *)buf; } if (pm8001_ha->fatal_bar_loc < (64 * 1024)) { pm8001_ha->forensic_info.data_buf.direct_data += sprintf(pm8001_ha-> forensic_info.data_buf.direct_data, "%08x ", 2); for (index = 0; index < (SYSFS_OFFSET / 4); index++) { pm8001_ha->forensic_info.data_buf.direct_data += sprintf(pm8001_ha-> forensic_info.data_buf.direct_data, "%08x ", *(temp + index)); } return (char *)pm8001_ha-> forensic_info.data_buf.direct_data - (char *)buf; } /* Increment the MEMBASE II Shifting Register value by 0x100.*/ pm8001_ha->forensic_info.data_buf.direct_data += sprintf(pm8001_ha->forensic_info.data_buf.direct_data, "%08x ", 2); for (index = 0; index < 256; index++) { pm8001_ha->forensic_info.data_buf.direct_data += sprintf(pm8001_ha-> forensic_info.data_buf.direct_data, "%08x ", *(temp + index)); } pm8001_ha->fatal_forensic_shift_offset += 0x100; pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER, pm8001_ha->fatal_forensic_shift_offset); pm8001_ha->fatal_bar_loc = 0; return (char *)pm8001_ha->forensic_info.data_buf.direct_data - (char *)buf; } if (pm8001_ha->forensic_fatal_step == 1) { pm8001_ha->fatal_forensic_shift_offset = 0; /* Read 64K of the debug data. */ pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER, pm8001_ha->fatal_forensic_shift_offset); pm8001_mw32(fatal_table_address, MPI_FATAL_EDUMP_TABLE_HANDSHAKE, MPI_FATAL_EDUMP_HANDSHAKE_RDY); /* Poll FDDHSHK until clear */ start = jiffies + (2 * HZ); /* 2 sec */ do { reg_val = pm8001_mr32(fatal_table_address, MPI_FATAL_EDUMP_TABLE_HANDSHAKE); } while ((reg_val) && time_before(jiffies, start)); if (reg_val != 0) { PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("TIMEOUT:MEMBASE_II_SHIFT_REGISTER" " = 0x%x\n", reg_val)); return -EIO; } /* Read the next 64K of the debug data. */ pm8001_ha->forensic_fatal_step = 0; if (pm8001_mr32(fatal_table_address, MPI_FATAL_EDUMP_TABLE_STATUS) != MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE) { pm8001_mw32(fatal_table_address, MPI_FATAL_EDUMP_TABLE_HANDSHAKE, 0); goto moreData; } else { pm8001_ha->forensic_info.data_buf.direct_data += sprintf(pm8001_ha-> forensic_info.data_buf.direct_data, "%08x ", 4); pm8001_ha->forensic_info.data_buf.read_len = 0xFFFFFFFF; pm8001_ha->forensic_info.data_buf.direct_len = 0; pm8001_ha->forensic_info.data_buf.direct_offset = 0; pm8001_ha->forensic_info.data_buf.read_len = 0; } } return (char *)pm8001_ha->forensic_info.data_buf.direct_data - (char *)buf; }