ips.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,776 行 · 第 1/5 页
C
1,776 行
IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Complete.\n"); ips_sh[i] = NULL; ips_ha[i] = NULL; /* free extra memory */ ips_free(ha); /* Free I/O Region */ if (ha->io_addr) release_region(ha->io_addr, ha->io_len); /* free IRQ */ free_irq(ha->irq, ha); IPS_REMOVE_HOST(sh); scsi_host_put(sh); ips_released_controllers++; return (FALSE);}/****************************************************************************//* *//* Routine Name: ips_halt *//* *//* Routine Description: *//* *//* Perform cleanup when the system reboots *//* *//****************************************************************************/static intips_halt(struct notifier_block *nb, ulong event, void *buf){ ips_scb_t *scb; ips_ha_t *ha; int i; if ((event != SYS_RESTART) && (event != SYS_HALT) && (event != SYS_POWER_OFF)) return (NOTIFY_DONE); for (i = 0; i < ips_next_controller; i++) { ha = (ips_ha_t *) ips_ha[i]; if (!ha) continue; if (!ha->active) continue; /* flush the cache on the controller */ scb = &ha->scbs[ha->max_cmds - 1]; ips_init_scb(ha, scb); scb->timeout = ips_cmd_timeout; scb->cdb[0] = IPS_CMD_FLUSH; scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH; scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb); scb->cmd.flush_cache.state = IPS_NORM_STATE; scb->cmd.flush_cache.reserved = 0; scb->cmd.flush_cache.reserved2 = 0; scb->cmd.flush_cache.reserved3 = 0; scb->cmd.flush_cache.reserved4 = 0; IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Cache.\n"); /* send command */ if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) == IPS_FAILURE) IPS_PRINTK(KERN_WARNING, ha->pcidev, "Incomplete Flush.\n"); else IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Complete.\n"); } return (NOTIFY_OK);}/****************************************************************************//* *//* Routine Name: ips_eh_abort *//* *//* Routine Description: *//* *//* Abort a command (using the new error code stuff) *//* Note: this routine is called under the io_request_lock *//****************************************************************************/intips_eh_abort(Scsi_Cmnd * SC){ ips_ha_t *ha; ips_copp_wait_item_t *item; int ret; METHOD_TRACE("ips_eh_abort", 1); if (!SC) return (FAILED); ha = (ips_ha_t *) SC->device->host->hostdata; if (!ha) return (FAILED); if (!ha->active) return (FAILED); if (SC->serial_number != SC->serial_number_at_timeout) { /* HMM, looks like a bogus command */ DEBUG(1, "Abort called with bogus scsi command"); return (FAILED); } /* See if the command is on the copp queue */ item = ha->copp_waitlist.head; while ((item) && (item->scsi_cmd != SC)) item = item->next; if (item) { /* Found it */ ips_removeq_copp(&ha->copp_waitlist, item); ret = (SUCCESS); /* See if the command is on the wait queue */ } else if (ips_removeq_wait(&ha->scb_waitlist, SC)) { /* command not sent yet */ ret = (SUCCESS); } else { /* command must have already been sent */ ret = (FAILED); } return ret;}/****************************************************************************//* *//* Routine Name: ips_eh_reset *//* *//* Routine Description: *//* *//* Reset the controller (with new eh error code) *//* *//* NOTE: this routine is called under the io_request_lock spinlock *//* *//****************************************************************************/intips_eh_reset(Scsi_Cmnd * SC){ int ret; int i; ips_ha_t *ha; ips_scb_t *scb; ips_copp_wait_item_t *item; METHOD_TRACE("ips_eh_reset", 1);#ifdef NO_IPS_RESET return (FAILED);#else if (!SC) { DEBUG(1, "Reset called with NULL scsi command"); return (FAILED); } ha = (ips_ha_t *) SC->device->host->hostdata; if (!ha) { DEBUG(1, "Reset called with NULL ha struct"); return (FAILED); } if (!ha->active) return (FAILED); /* See if the command is on the copp queue */ item = ha->copp_waitlist.head; while ((item) && (item->scsi_cmd != SC)) item = item->next; if (item) { /* Found it */ ips_removeq_copp(&ha->copp_waitlist, item); return (SUCCESS); } /* See if the command is on the wait queue */ if (ips_removeq_wait(&ha->scb_waitlist, SC)) { /* command not sent yet */ return (SUCCESS); } /* An explanation for the casual observer: */ /* Part of the function of a RAID controller is automatic error */ /* detection and recovery. As such, the only problem that physically */ /* resetting an adapter will ever fix is when, for some reason, */ /* the driver is not successfully communicating with the adapter. */ /* Therefore, we will attempt to flush this adapter. If that succeeds, */ /* then there's no real purpose in a physical reset. This will complete */ /* much faster and avoids any problems that might be caused by a */ /* physical reset ( such as having to fail all the outstanding I/O's ). */ if (ha->ioctl_reset == 0) { /* IF Not an IOCTL Requested Reset */ scb = &ha->scbs[ha->max_cmds - 1]; ips_init_scb(ha, scb); scb->timeout = ips_cmd_timeout; scb->cdb[0] = IPS_CMD_FLUSH; scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH; scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb); scb->cmd.flush_cache.state = IPS_NORM_STATE; scb->cmd.flush_cache.reserved = 0; scb->cmd.flush_cache.reserved2 = 0; scb->cmd.flush_cache.reserved3 = 0; scb->cmd.flush_cache.reserved4 = 0; /* Attempt the flush command */ ret = ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_IORL); if (ret == IPS_SUCCESS) { IPS_PRINTK(KERN_NOTICE, ha->pcidev, "Reset Request - Flushed Cache\n"); return (SUCCESS); } } /* Either we can't communicate with the adapter or it's an IOCTL request */ /* from a utility. A physical reset is needed at this point. */ ha->ioctl_reset = 0; /* Reset the IOCTL Requested Reset Flag */ /* * command must have already been sent * reset the controller */ IPS_PRINTK(KERN_NOTICE, ha->pcidev, "Resetting controller.\n"); ret = (*ha->func.reset) (ha); if (!ret) { Scsi_Cmnd *scsi_cmd; IPS_PRINTK(KERN_NOTICE, ha->pcidev, "Controller reset failed - controller now offline.\n"); /* Now fail all of the active commands */ DEBUG_VAR(1, "(%s%d) Failing active commands", ips_name, ha->host_num); while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) { scb->scsi_cmd->result = DID_ERROR << 16; scb->scsi_cmd->scsi_done(scb->scsi_cmd); ips_freescb(ha, scb); } /* Now fail all of the pending commands */ DEBUG_VAR(1, "(%s%d) Failing pending commands", ips_name, ha->host_num); while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) { scsi_cmd->result = DID_ERROR; scsi_cmd->scsi_done(scsi_cmd); } ha->active = FALSE; return (FAILED); } if (!ips_clear_adapter(ha, IPS_INTR_IORL)) { Scsi_Cmnd *scsi_cmd; IPS_PRINTK(KERN_NOTICE, ha->pcidev, "Controller reset failed - controller now offline.\n"); /* Now fail all of the active commands */ DEBUG_VAR(1, "(%s%d) Failing active commands", ips_name, ha->host_num); while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) { scb->scsi_cmd->result = DID_ERROR << 16; scb->scsi_cmd->scsi_done(scb->scsi_cmd); ips_freescb(ha, scb); } /* Now fail all of the pending commands */ DEBUG_VAR(1, "(%s%d) Failing pending commands", ips_name, ha->host_num); while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) { scsi_cmd->result = DID_ERROR << 16; scsi_cmd->scsi_done(scsi_cmd); } ha->active = FALSE; return (FAILED); } /* FFDC */ if (le32_to_cpu(ha->subsys->param[3]) & 0x300000) { struct timeval tv; do_gettimeofday(&tv); ha->last_ffdc = tv.tv_sec; ha->reset_count++; ips_ffdc_reset(ha, IPS_INTR_IORL); } /* Now fail all of the active commands */ DEBUG_VAR(1, "(%s%d) Failing active commands", ips_name, ha->host_num); while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) { scb->scsi_cmd->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24); scb->scsi_cmd->scsi_done(scb->scsi_cmd); ips_freescb(ha, scb); } /* Reset DCDB active command bits */ for (i = 1; i < ha->nbus; i++) ha->dcdb_active[i - 1] = 0; /* Reset the number of active IOCTLs */ ha->num_ioctl = 0; ips_next(ha, IPS_INTR_IORL); return (SUCCESS);#endif /* NO_IPS_RESET */}/****************************************************************************//* *//* Routine Name: ips_queue *//* *//* Routine Description: *//* *//* Send a command to the controller *//* *//* NOTE: *//* Linux obtains io_request_lock before calling this function *//* *//****************************************************************************/intips_queue(Scsi_Cmnd * SC, void (*done) (Scsi_Cmnd *)){ ips_ha_t *ha; ips_passthru_t *pt;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?