Commit 4a4b2d76 authored by Stephen M. Cameron's avatar Stephen M. Cameron Committed by Jens Axboe

cciss: factor out core of sendcmd() for a more sane interface

Factor out the core of sendcmd() to provide a simpler interface which
exposes all the error information to the caller and make the original
sendcmd use this new function.  Rationale: The SCSI error handling
routines need to send commands with interrupts turned off, but they also
need access to the full error information.
Signed-off-by: default avatarStephen M. Cameron <scameron@beardog.cca.cpqcorp.net>
Cc: Mike Miller <mikem@beardog.cca.cpqcorp.net>
Signed-off-by: default avatarJens Axboe <jens.axboe@oracle.com>
parent 53c663ce
...@@ -2373,41 +2373,21 @@ static int add_sendcmd_reject(__u8 cmd, int ctlr, unsigned long complete) ...@@ -2373,41 +2373,21 @@ static int add_sendcmd_reject(__u8 cmd, int ctlr, unsigned long complete)
return 0; return 0;
} }
/* /* Send command c to controller h and poll for it to complete.
* Send a command to the controller, and wait for it to complete. * Turns interrupts off on the board. Used at driver init time
* Only used at init time. * and during SCSI error recovery.
*/ */
static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, unsigned int use_unit_num, /* 0: address the controller, static int sendcmd_core(ctlr_info_t *h, CommandList_struct *c)
1: address logical volume log_unit,
2: periph device address is scsi3addr */
unsigned int log_unit,
__u8 page_code, unsigned char *scsi3addr, int cmd_type)
{ {
CommandList_struct *c;
int i; int i;
unsigned long complete; unsigned long complete;
ctlr_info_t *info_p = hba[ctlr]; int status = IO_ERROR;
u64bit buff_dma_handle; u64bit buff_dma_handle;
int status, done = 0;
if ((c = cmd_alloc(info_p, 1)) == NULL) { resend_cmd1:
printk(KERN_WARNING "cciss: unable to get memory");
return IO_ERROR; /* Disable interrupt on the board. */
} h->access.set_intr_mask(h, CCISS_INTR_OFF);
status = fill_cmd(c, cmd, ctlr, buff, size, use_unit_num,
log_unit, page_code, scsi3addr, cmd_type);
if (status != IO_OK) {
cmd_free(info_p, c, 1);
return status;
}
resend_cmd1:
/*
* Disable interrupt
*/
#ifdef CCISS_DEBUG
printk(KERN_DEBUG "cciss: turning intr off\n");
#endif /* CCISS_DEBUG */
info_p->access.set_intr_mask(info_p, CCISS_INTR_OFF);
/* Make sure there is room in the command FIFO */ /* Make sure there is room in the command FIFO */
/* Actually it should be completely empty at this time */ /* Actually it should be completely empty at this time */
...@@ -2415,21 +2395,15 @@ static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, unsigned int use ...@@ -2415,21 +2395,15 @@ static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, unsigned int use
/* tape side of the driver. */ /* tape side of the driver. */
for (i = 200000; i > 0; i--) { for (i = 200000; i > 0; i--) {
/* if fifo isn't full go */ /* if fifo isn't full go */
if (!(info_p->access.fifo_full(info_p))) { if (!(h->access.fifo_full(h)))
break; break;
}
udelay(10); udelay(10);
printk(KERN_WARNING "cciss cciss%d: SendCmd FIFO full," printk(KERN_WARNING "cciss cciss%d: SendCmd FIFO full,"
" waiting!\n", ctlr); " waiting!\n", h->ctlr);
} }
/* h->access.submit_command(h, c); /* Send the cmd */
* Send the cmd
*/
info_p->access.submit_command(info_p, c);
done = 0;
do { do {
complete = pollcomplete(ctlr); complete = pollcomplete(h->ctlr);
#ifdef CCISS_DEBUG #ifdef CCISS_DEBUG
printk(KERN_DEBUG "cciss: command completed\n"); printk(KERN_DEBUG "cciss: command completed\n");
...@@ -2438,97 +2412,116 @@ static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, unsigned int use ...@@ -2438,97 +2412,116 @@ static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, unsigned int use
if (complete == 1) { if (complete == 1) {
printk(KERN_WARNING printk(KERN_WARNING
"cciss cciss%d: SendCmd Timeout out, " "cciss cciss%d: SendCmd Timeout out, "
"No command list address returned!\n", ctlr); "No command list address returned!\n", h->ctlr);
status = IO_ERROR; status = IO_ERROR;
done = 1;
break; break;
} }
/* This will need to change for direct lookup completions */ /* If it's not the cmd we're looking for, save it for later */
if ((complete & CISS_ERROR_BIT) if ((complete & ~CISS_ERROR_BIT) != c->busaddr) {
&& (complete & ~CISS_ERROR_BIT) == c->busaddr) { if (add_sendcmd_reject(c->Request.CDB[0],
/* if data overrun or underun on Report command h->ctlr, complete) != 0)
ignore it BUG(); /* we are hosed if we get here. */
*/ continue;
if (((c->Request.CDB[0] == CISS_REPORT_LOG) || }
(c->Request.CDB[0] == CISS_REPORT_PHYS) ||
(c->Request.CDB[0] == CISS_INQUIRY)) && /* It is our command. If no error, we're done. */
((c->err_info->CommandStatus == if (!(complete & CISS_ERROR_BIT)) {
CMD_DATA_OVERRUN) || status = IO_OK;
(c->err_info->CommandStatus == CMD_DATA_UNDERRUN) break;
)) { }
complete = c->busaddr;
} else { /* There is an error... */
if (c->err_info->CommandStatus ==
CMD_UNSOLICITED_ABORT) { /* if data overrun or underun on Report command ignore it */
printk(KERN_WARNING "cciss%d: " if (((c->Request.CDB[0] == CISS_REPORT_LOG) ||
"unsolicited abort %p\n", (c->Request.CDB[0] == CISS_REPORT_PHYS) ||
ctlr, c); (c->Request.CDB[0] == CISS_INQUIRY)) &&
if (c->retry_count < MAX_CMD_RETRIES) { ((c->err_info->CommandStatus == CMD_DATA_OVERRUN) ||
printk(KERN_WARNING (c->err_info->CommandStatus == CMD_DATA_UNDERRUN))) {
"cciss%d: retrying %p\n", complete = c->busaddr;
ctlr, c); status = IO_OK;
c->retry_count++; break;
/* erase the old error */
/* information */
memset(c->err_info, 0,
sizeof
(ErrorInfo_struct));
goto resend_cmd1;
} else {
printk(KERN_WARNING
"cciss%d: retried %p too "
"many times\n", ctlr, c);
status = IO_ERROR;
goto cleanup1;
}
} else if (c->err_info->CommandStatus ==
CMD_UNABORTABLE) {
printk(KERN_WARNING
"cciss%d: command could not be aborted.\n",
ctlr);
status = IO_ERROR;
goto cleanup1;
}
printk(KERN_WARNING "ciss ciss%d: sendcmd"
" Error %x \n", ctlr,
c->err_info->CommandStatus);
printk(KERN_WARNING "ciss ciss%d: sendcmd"
" offensive info\n"
" size %x\n num %x value %x\n",
ctlr,
c->err_info->MoreErrInfo.Invalid_Cmd.
offense_size,
c->err_info->MoreErrInfo.Invalid_Cmd.
offense_num,
c->err_info->MoreErrInfo.Invalid_Cmd.
offense_value);
status = IO_ERROR;
goto cleanup1;
}
} }
/* This will need changing for direct lookup completions */
if (complete != c->busaddr) { if (c->err_info->CommandStatus == CMD_UNSOLICITED_ABORT) {
if (add_sendcmd_reject(cmd, ctlr, complete) != 0) { printk(KERN_WARNING "cciss%d: unsolicited abort %p\n",
BUG(); /* we are pretty much hosed if we get here. */ h->ctlr, c);
if (c->retry_count < MAX_CMD_RETRIES) {
printk(KERN_WARNING "cciss%d: retrying %p\n",
h->ctlr, c);
c->retry_count++;
/* erase the old error information */
memset(c->err_info, 0, sizeof(c->err_info));
goto resend_cmd1;
} }
continue; printk(KERN_WARNING "cciss%d: retried %p too many "
} else "times\n", h->ctlr, c);
done = 1; status = IO_ERROR;
} while (!done); goto cleanup1;
}
if (c->err_info->CommandStatus == CMD_UNABORTABLE) {
printk(KERN_WARNING "cciss%d: command could not be "
"aborted.\n", h->ctlr);
status = IO_ERROR;
goto cleanup1;
}
printk(KERN_WARNING "cciss%d: sendcmd error\n", h->ctlr);
printk(KERN_WARNING "cmd = 0x%02x, CommandStatus = 0x%02x\n",
c->Request.CDB[0], c->err_info->CommandStatus);
if (c->err_info->CommandStatus == CMD_TARGET_STATUS) {
printk(KERN_WARNING "Target status = 0x%02x\n",
c->err_info->ScsiStatus);
if (c->err_info->ScsiStatus == 2) /* chk cond */
printk(KERN_WARNING "Sense key = 0x%02x\n",
0xf & c->err_info->SenseInfo[2]);
}
status = IO_ERROR;
goto cleanup1;
} while (1);
cleanup1: cleanup1:
/* unlock the data buffer from DMA */ /* unlock the data buffer from DMA */
buff_dma_handle.val32.lower = c->SG[0].Addr.lower; buff_dma_handle.val32.lower = c->SG[0].Addr.lower;
buff_dma_handle.val32.upper = c->SG[0].Addr.upper; buff_dma_handle.val32.upper = c->SG[0].Addr.upper;
pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val, pci_unmap_single(h->pdev, (dma_addr_t) buff_dma_handle.val,
c->SG[0].Len, PCI_DMA_BIDIRECTIONAL); c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
#ifdef CONFIG_CISS_SCSI_TAPE #ifdef CONFIG_CISS_SCSI_TAPE
/* if we saved some commands for later, process them now. */ /* if we saved some commands for later, process them now. */
if (info_p->scsi_rejects.ncompletions > 0) if (h->scsi_rejects.ncompletions > 0)
do_cciss_intr(0, info_p); do_cciss_intr(0, h);
#endif #endif
cmd_free(info_p, c, 1); return status;
}
/*
* Send a command to the controller, and wait for it to complete.
* Used at init time, and during SCSI error recovery.
*/
static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size,
unsigned int use_unit_num,/* 0: address the controller,
1: address logical volume log_unit,
2: periph device address is scsi3addr */
unsigned int log_unit,
__u8 page_code, unsigned char *scsi3addr, int cmd_type)
{
CommandList_struct *c;
int status;
c = cmd_alloc(hba[ctlr], 1);
if (!c) {
printk(KERN_WARNING "cciss: unable to get memory");
return IO_ERROR;
}
status = fill_cmd(c, cmd, ctlr, buff, size, use_unit_num,
log_unit, page_code, scsi3addr, cmd_type);
if (status == IO_OK)
status = sendcmd_core(hba[ctlr], c);
cmd_free(hba[ctlr], c, 1);
return status; return status;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment