static void ips_read_nvram_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error) { ips_softc_t *sc; ips_command_t *command = cmdptr; ips_rw_nvram_cmd *command_struct; sc = command->sc; if(error){ ips_set_error(command, error); printf("ips: error = %d in ips_read_nvram_callback\n", error); return; } command_struct = (ips_rw_nvram_cmd *)command->command_buffer; command_struct->command = IPS_RW_NVRAM_CMD; command_struct->id = command->id; command_struct->pagenum = 5; command_struct->rw = 0; command_struct->buffaddr = segments[0].ds_addr; bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, BUS_DMASYNC_PREWRITE); bus_dmamap_sync(command->data_dmatag, command->data_dmamap, BUS_DMASYNC_PREREAD); sc->ips_issue_cmd(command); if (sema_timedwait(&sc->cmd_sema, 30*hz) != 0) { ips_set_error(command, ETIMEDOUT); return; } bus_dmamap_sync(command->data_dmatag, command->data_dmamap, BUS_DMASYNC_POSTWRITE); }
/* Below are a series of functions for sending a drive info request * to the adapter. The flow order is: get, send, callback. It uses * the generic finish callback at the top of this file. * This can be used to get drive status info from the card */ static void ips_drive_info_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error) { ips_softc_t *sc; ips_command_t *command = cmdptr; ips_drive_cmd *command_struct; ips_drive_info_t *driveinfo; sc = command->sc; if(error){ ips_set_error(command, error); printf("ips: error = %d in ips_get_drive_info\n", error); return; } command_struct = (ips_drive_cmd *)command->command_buffer; command_struct->command = IPS_DRIVE_INFO_CMD; command_struct->id = command->id; command_struct->buffaddr = segments[0].ds_addr; bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, BUS_DMASYNC_PREWRITE); bus_dmamap_sync(command->data_dmatag, command->data_dmamap, BUS_DMASYNC_PREREAD); sc->ips_issue_cmd(command); if (sema_timedwait(&sc->cmd_sema, 10*hz) != 0) { ips_set_error(command, ETIMEDOUT); return; } bus_dmamap_sync(command->data_dmatag, command->data_dmamap, BUS_DMASYNC_POSTREAD); driveinfo = command->data_buffer; memcpy(sc->drives, driveinfo->drives, sizeof(ips_drive_t) * 8); sc->drivecount = driveinfo->drivecount; device_printf(sc->dev, "logical drives: %d\n",sc->drivecount); }
/* Below are a series of functions for sending an adapter info request * to the adapter. The flow order is: get, send, callback. It uses * the generic finish callback at the top of this file. * This can be used to get configuration/status info from the card */ static void ips_adapter_info_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error) { ips_softc_t *sc; ips_command_t *command = cmdptr; ips_adapter_info_cmd *command_struct; sc = command->sc; if(error){ ips_set_error(command, error); printf("ips: error = %d in ips_get_adapter_info\n", error); return; } command_struct = (ips_adapter_info_cmd *)command->command_buffer; command_struct->command = IPS_ADAPTER_INFO_CMD; command_struct->id = command->id; command_struct->buffaddr = segments[0].ds_addr; bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, BUS_DMASYNC_PREWRITE); bus_dmamap_sync(command->data_dmatag, command->data_dmamap, BUS_DMASYNC_PREREAD); sc->ips_issue_cmd(command); if (sema_timedwait(&sc->cmd_sema, 30*hz) != 0) { ips_set_error(command, ETIMEDOUT); return; } bus_dmamap_sync(command->data_dmatag, command->data_dmamap, BUS_DMASYNC_POSTREAD); memcpy(&(sc->adapter_info), command->data_buffer, IPS_ADAPTER_INFO_LEN); }
void ips_issue_morpheus_cmd(ips_command_t *command) { /* hmmm, is there a cleaner way to do this? */ if(command->sc->state & IPS_OFFLINE){ ips_set_error(command, EINVAL); command->callback(command); return; } command->timeout = 10; ips_write_4(command->sc, MORPHEUS_REG_IQPR, command->command_phys_addr); }
void ips_issue_copperhead_cmd(ips_command_t *command) { int i; /* hmmm, is there a cleaner way to do this? */ if(command->sc->state & IPS_OFFLINE){ ips_set_error(command, EINVAL); command->callback(command); return; } command->timeout = 10; for(i = 0; ips_read_4(command->sc, COPPER_REG_CCCR) & COPPER_SEM_BIT; i++ ){ if( i == 20){ printf("sem bit still set, can't send a command\n"); return; } DELAY(500);/* need to do a delay here */ } ips_write_4(command->sc, COPPER_REG_CCSAR, command->command_phys_addr); ips_write_2(command->sc, COPPER_REG_CCCR, COPPER_CMD_START); }
static void ips_ioctl_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error) { ips_command_t *command = cmdptr; ips_ioctl_t *ioctl_cmd = command->arg; ips_generic_cmd *command_buffer = command->command_buffer; if(error){ ips_set_error(command, error); return; } command_buffer->id = command->id; command_buffer->buffaddr = segments[0].ds_addr; if(ioctl_cmd->readwrite & IPS_IOCTL_WRITE){ bus_dmamap_sync(ioctl_cmd->dmatag, ioctl_cmd->dmamap, BUS_DMASYNC_PREWRITE); } else if(ioctl_cmd->readwrite & IPS_IOCTL_READ){ bus_dmamap_sync(ioctl_cmd->dmatag, ioctl_cmd->dmamap, BUS_DMASYNC_PREREAD); } bus_dmamap_sync(command->sc->command_dmatag, command->command_dmamap, BUS_DMASYNC_PREWRITE); command->sc->ips_issue_cmd(command); }
/* ips_timeout is periodically called to make sure no commands sent * to the card have become stuck. If it finds a stuck command, it * sets a flag so the driver won't start any more commands and then * is periodically called to see if all outstanding commands have * either finished or timed out. Once timed out, an attempt to * reinitialize the card is made. If that fails, the driver gives * up and declares the card dead. */ static void ips_timeout(void *arg) { ips_softc_t *sc = arg; int i, state = 0; ips_command_t *command; mtx_lock(&sc->queue_mtx); command = &sc->commandarray[0]; for(i = 0; i < sc->max_cmds; i++){ if(!command[i].timeout){ continue; } command[i].timeout--; if(!command[i].timeout){ if(!(sc->state & IPS_TIMEOUT)){ sc->state |= IPS_TIMEOUT; device_printf(sc->dev, "WARNING: command timeout. Adapter is in toaster mode, resetting to known state\n"); } ips_set_error(&command[i], ETIMEDOUT); command[i].callback(&command[i]); /* hmm, this should be enough cleanup */ } else state = 1; } if(!state && (sc->state & IPS_TIMEOUT)){ if(sc->ips_adapter_reinit(sc, 1)){ device_printf(sc->dev, "AIEE! adapter reset failed, giving up and going home! Have a nice day.\n"); sc->state |= IPS_OFFLINE; sc->state &= ~IPS_TIMEOUT; /* Grr, I hate this solution. I run waiting commands one at a time and error them out just before they would go to the card. This sucks. */ } else sc->state &= ~IPS_TIMEOUT; } if (sc->state != IPS_OFFLINE) sc->timer = timeout(ips_timeout, sc, 10*hz); mtx_unlock(&sc->queue_mtx); }