📄 cciss_scsi.c
字号:
} else if (found == 1) { /* should never happen... */ changes++; printk("cciss%d: device unexpectedly changed type\n", ctlr); /* but if it does happen, we just ignore that device */ } } CPQ_TAPE_UNLOCK(ctlr, flags); if (!changes) printk("cciss%d: No device changes detected.\n", ctlr); return 0;}static intlookup_scsi3addr(int ctlr, int bus, int target, int lun, char *scsi3addr){ int i; struct cciss_scsi_dev_t *sd; unsigned long flags; CPQ_TAPE_LOCK(ctlr, flags); for (i=0;i<ccissscsi[ctlr].ndevices;i++) { sd = &ccissscsi[ctlr].dev[i]; if (sd->bus == bus && sd->target == target && sd->lun == lun) { memcpy(scsi3addr, &sd->scsi3addr[0], 8); CPQ_TAPE_UNLOCK(ctlr, flags); return 0; } } CPQ_TAPE_UNLOCK(ctlr, flags); return -1;}static void cciss_scsi_setup(int cntl_num){ struct cciss_scsi_adapter_data_t * shba; ccissscsi[cntl_num].ndevices = 0; shba = (struct cciss_scsi_adapter_data_t *) kmalloc(sizeof(*shba), GFP_KERNEL); if (shba == NULL) return; shba->scsi_host = NULL; spin_lock_init(&shba->lock); shba->registered = 0; if (scsi_cmd_stack_setup(cntl_num, shba) != 0) { kfree(shba); shba = NULL; } hba[cntl_num]->scsi_ctlr = (void *) shba; return;}static voidcomplete_scsi_command( CommandList_struct *cp, int timeout, __u32 tag){ struct scsi_cmnd *cmd; ctlr_info_t *ctlr; u64bit addr64; ErrorInfo_struct *ei; ei = cp->err_info; /* First, see if it was a message rather than a command */ if (cp->Request.Type.Type == TYPE_MSG) { cp->cmd_type = CMD_MSG_DONE; return; } cmd = (struct scsi_cmnd *) cp->scsi_cmd; ctlr = hba[cp->ctlr]; /* undo the DMA mappings */ if (cmd->use_sg) { pci_unmap_sg(ctlr->pdev, cmd->buffer, cmd->use_sg, cmd->sc_data_direction); } else if (cmd->request_bufflen) { addr64.val32.lower = cp->SG[0].Addr.lower; addr64.val32.upper = cp->SG[0].Addr.upper; pci_unmap_single(ctlr->pdev, (dma_addr_t) addr64.val, cmd->request_bufflen, cmd->sc_data_direction); } cmd->result = (DID_OK << 16); /* host byte */ cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */ /* cmd->result |= (GOOD < 1); */ /* status byte */ cmd->result |= (ei->ScsiStatus); /* printk("Scsistatus is 0x%02x\n", ei->ScsiStatus); */ /* copy the sense data whether we need to or not. */ memcpy(cmd->sense_buffer, ei->SenseInfo, ei->SenseLen > SCSI_SENSE_BUFFERSIZE ? SCSI_SENSE_BUFFERSIZE : ei->SenseLen); cmd->resid = ei->ResidualCnt; if(ei->CommandStatus != 0) { /* an error has occurred */ switch(ei->CommandStatus) { case CMD_TARGET_STATUS: /* Pass it up to the upper layers... */ if( ei->ScsiStatus) {#if 0 printk(KERN_WARNING "cciss: cmd %p " "has SCSI Status = %x\n", cp, ei->ScsiStatus); #endif cmd->result |= (ei->ScsiStatus < 1); } else { /* scsi status is zero??? How??? */ /* Ordinarily, this case should never happen, but there is a bug in some released firmware revisions that allows it to happen if, for example, a 4100 backplane loses power and the tape drive is in it. We assume that it's a fatal error of some kind because we can't show that it wasn't. We will make it look like selection timeout since that is the most common reason for this to occur, and it's severe enough. */ cmd->result = DID_NO_CONNECT << 16; } break; case CMD_DATA_UNDERRUN: /* let mid layer handle it. */ break; case CMD_DATA_OVERRUN: printk(KERN_WARNING "cciss: cp %p has" " completed with data overrun " "reported\n", cp); break; case CMD_INVALID: { /* print_bytes(cp, sizeof(*cp), 1, 0); print_cmd(cp); */ /* We get CMD_INVALID if you address a non-existent tape drive instead of a selection timeout (no response). You will see this if you yank out a tape drive, then try to access it. This is kind of a shame because it means that any other CMD_INVALID (e.g. driver bug) will get interpreted as a missing target. */ cmd->result = DID_NO_CONNECT << 16; } break; case CMD_PROTOCOL_ERR: printk(KERN_WARNING "cciss: cp %p has " "protocol error \n", cp); break; case CMD_HARDWARE_ERR: cmd->result = DID_ERROR << 16; printk(KERN_WARNING "cciss: cp %p had " " hardware error\n", cp); break; case CMD_CONNECTION_LOST: cmd->result = DID_ERROR << 16; printk(KERN_WARNING "cciss: cp %p had " "connection lost\n", cp); break; case CMD_ABORTED: cmd->result = DID_ABORT << 16; printk(KERN_WARNING "cciss: cp %p was " "aborted\n", cp); break; case CMD_ABORT_FAILED: cmd->result = DID_ERROR << 16; printk(KERN_WARNING "cciss: cp %p reports " "abort failed\n", cp); break; case CMD_UNSOLICITED_ABORT: cmd->result = DID_ABORT << 16; printk(KERN_WARNING "cciss: cp %p aborted " "do to an unsolicited abort\n", cp); break; case CMD_TIMEOUT: cmd->result = DID_TIME_OUT << 16; printk(KERN_WARNING "cciss: cp %p timedout\n", cp); break; default: cmd->result = DID_ERROR << 16; printk(KERN_WARNING "cciss: cp %p returned " "unknown status %x\n", cp, ei->CommandStatus); } } // printk("c:%p:c%db%dt%dl%d ", cmd, ctlr->ctlr, cmd->channel, // cmd->target, cmd->lun); cmd->scsi_done(cmd); scsi_cmd_free(ctlr, cp);}static intcciss_scsi_detect(int ctlr){ struct Scsi_Host *sh; int error; sh = scsi_host_alloc(&cciss_driver_template, sizeof(struct ctlr_info *)); if (sh == NULL) goto fail; sh->io_port = 0; // good enough? FIXME, sh->n_io_port = 0; // I don't think we use these two... sh->this_id = SELF_SCSI_ID; ((struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr)->scsi_host = (void *) sh; sh->hostdata[0] = (unsigned long) hba[ctlr]; sh->irq = hba[ctlr]->intr; sh->unique_id = sh->irq; error = scsi_add_host(sh, &hba[ctlr]->pdev->dev); if (error) goto fail_host_put; scsi_scan_host(sh); return 1; fail_host_put: scsi_host_put(sh); fail: return 0;}static voidcciss_unmap_one(struct pci_dev *pdev, CommandList_struct *cp, size_t buflen, int data_direction){ u64bit addr64; addr64.val32.lower = cp->SG[0].Addr.lower; addr64.val32.upper = cp->SG[0].Addr.upper; pci_unmap_single(pdev, (dma_addr_t) addr64.val, buflen, data_direction);}static voidcciss_map_one(struct pci_dev *pdev, CommandList_struct *cp, unsigned char *buf, size_t buflen, int data_direction){ __u64 addr64; addr64 = (__u64) pci_map_single(pdev, buf, buflen, data_direction); cp->SG[0].Addr.lower = (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF); cp->SG[0].Addr.upper = (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF); cp->SG[0].Len = buflen; cp->Header.SGList = (__u8) 1; /* no. SGs contig in this cmd */ cp->Header.SGTotal = (__u16) 1; /* total sgs in this cmd list */}static intcciss_scsi_do_simple_cmd(ctlr_info_t *c, CommandList_struct *cp, unsigned char *scsi3addr, unsigned char *cdb, unsigned char cdblen, unsigned char *buf, int bufsize, int direction){ unsigned long flags; DECLARE_COMPLETION(wait); cp->cmd_type = CMD_IOCTL_PEND; // treat this like an ioctl cp->scsi_cmd = NULL; cp->Header.ReplyQueue = 0; // unused in simple mode memcpy(&cp->Header.LUN, scsi3addr, sizeof(cp->Header.LUN)); cp->Header.Tag.lower = cp->busaddr; // Use k. address of cmd as tag // Fill in the request block... /* printk("Using scsi3addr 0x%02x%0x2%0x2%0x2%0x2%0x2%0x2%0x2\n", scsi3addr[0], scsi3addr[1], scsi3addr[2], scsi3addr[3], scsi3addr[4], scsi3addr[5], scsi3addr[6], scsi3addr[7]); */ memset(cp->Request.CDB, 0, sizeof(cp->Request.CDB)); memcpy(cp->Request.CDB, cdb, cdblen); cp->Request.Timeout = 0; cp->Request.CDBLen = cdblen; cp->Request.Type.Type = TYPE_CMD; cp->Request.Type.Attribute = ATTR_SIMPLE; cp->Request.Type.Direction = direction; /* Fill in the SG list and do dma mapping */ cciss_map_one(c->pdev, cp, (unsigned char *) buf, bufsize, DMA_FROM_DEVICE); cp->waiting = &wait; /* Put the request on the tail of the request queue */ spin_lock_irqsave(CCISS_LOCK(c->ctlr), flags); addQ(&c->reqQ, cp); c->Qdepth++; start_io(c); spin_unlock_irqrestore(CCISS_LOCK(c->ctlr), flags); wait_for_completion(&wait); /* undo the dma mapping */ cciss_unmap_one(c->pdev, cp, bufsize, DMA_FROM_DEVICE); return(0);}static void cciss_scsi_interpret_error(CommandList_struct *cp){ ErrorInfo_struct *ei; ei = cp->err_info; switch(ei->CommandStatus) { case CMD_TARGET_STATUS: printk(KERN_WARNING "cciss: cmd %p has " "completed with errors\n", cp); printk(KERN_WARNING "cciss: cmd %p " "has SCSI Status = %x\n", cp, ei->ScsiStatus); if (ei->ScsiStatus == 0) printk(KERN_WARNING "cciss:SCSI status is abnormally zero. " "(probably indicates selection timeout " "reported incorrectly due to a known " "firmware bug, circa July, 2001.)\n"); break; case CMD_DATA_UNDERRUN: /* let mid layer handle it. */ printk("UNDERRUN\n"); break; case CMD_DATA_OVERRUN: printk(KERN_WARNING "cciss: cp %p has" " completed with data overrun " "reported\n", cp); break; case CMD_INVALID: { /* controller unfortunately reports SCSI passthru's */ /* to non-existent targets as invalid commands. */ printk(KERN_WARNING "cciss: cp %p is " "reported invalid (probably means " "target device no longer present)\n", cp); /* print_bytes((unsigned char *) cp, sizeof(*cp), 1, 0); print_cmd(cp); */ } break; case CMD_PROTOCOL_ERR: printk(KERN_WARNING "cciss: cp %p has " "protocol error \n", cp); break; case CMD_HARDWARE_ERR: /* cmd->result = DID_ERROR << 16; */ printk(KERN_WARNING "cciss: cp %p had " " hardware error\n", cp); break; case CMD_CONNECTION_LOST: printk(KERN_WARNING "cciss: cp %p had " "connection lost\n", cp); break; case CMD_ABORTED: printk(KERN_WARNING "cciss: cp %p was " "aborted\n", cp); break; case CMD_ABORT_FAILED: printk(KERN_WARNING "cciss: cp %p reports " "abort failed\n", cp); break; case CMD_UNSOLICITED_ABORT: printk(KERN_WARNING "cciss: cp %p aborted " "do to an unsolicited abort\n", cp); break; case CMD_TIMEOUT: printk(KERN_WARNING "cciss: cp %p timedout\n", cp); break; default: printk(KERN_WARNING "cciss: cp %p returned " "unknown status %x\n", cp, ei->CommandStatus); }}static intcciss_scsi_do_inquiry(ctlr_info_t *c, unsigned char *scsi3addr, unsigned char *buf, unsigned char bufsize){ int rc; CommandList_struct *cp; char cdb[6]; ErrorInfo_struct *ei; unsigned long flags; spin_lock_irqsave(CCISS_LOCK(c->ctlr), flags); cp = scsi_cmd_alloc(c); spin_unlock_irqrestore(CCISS_LOCK(c->ctlr), flags); if (cp == NULL) { /* trouble... */ printk("cmd_alloc returned NULL!\n"); return -1; } ei = cp->err_info; cdb[0] = CISS_INQUIRY; cdb[1] = 0; cdb[2] = 0; cdb[3] = 0; cdb[4] = bufsize; cdb[5] = 0; rc = cciss_scsi_do_simple_cmd(c, cp, scsi3addr, cdb, 6, buf, bufsize, XFER_READ); if (rc != 0) return rc; /* something went wrong */ if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) { cciss_scsi_interpret_error(cp); rc = -1; } spin_lock_irqsave(CCISS_LOCK(c->ctlr), flags); scsi_cmd_free(c, cp); spin_unlock_irqrestore(CCISS_LOCK(c->ctlr), flags); return rc; }static intcciss_scsi_do_report_phys_luns(ctlr_info_t *c, ReportLunData_struct *buf, int bufsize){ int rc; CommandList_struct *cp; unsigned char cdb[12]; unsigned char scsi3addr[8]; ErrorInfo_struct *ei; unsigned long flags; spin_lock_irqsave(CCISS_LOCK(c->ctlr), flags); cp = scsi_cmd_alloc(c); spin_unlock_irqrestore(CCISS_LOCK(c->ctlr), flags); if (cp == NULL) { /* trouble... */ printk("cmd_alloc returned NULL!\n"); return -1; } memset(&scsi3addr[0], 0, 8); /* address the controller */ cdb[0] = CISS_REPORT_PHYS; cdb[1] = 0; cdb[2] = 0; cdb[3] = 0; cdb[4] = 0; cdb[5] = 0; cdb[6] = (bufsize >> 24) & 0xFF; //MSB cdb[7] = (bufsize >> 16) & 0xFF; cdb[8] = (bufsize >> 8) & 0xFF; cdb[9] = bufsize & 0xFF; cdb[10] = 0; cdb[11] = 0; rc = cciss_scsi_do_simple_cmd(c, cp, scsi3addr, cdb, 12, (unsigned char *) buf, bufsize, XFER_READ); if (rc != 0) return rc; /* something went wrong */ ei = cp->err_info; if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) { cciss_scsi_interpret_error(cp); rc = -1; } spin_lock_irqsave(CCISS_LOCK(c->ctlr), flags); scsi_cmd_free(c, cp); spin_unlock_irqrestore(CCISS_LOCK(c->ctlr), flags); return rc; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -