[SCSI] update fc_transport for removal of block/unblock functions
[linux-2.6.git] / drivers / scsi / lpfc / lpfc_scsi.c
index 13da26883da31ca82fe0f8c480f3468c3ca4cb18..c55ab1a630e5ddf24c32f72edf2b526c3538e0a2 100644 (file)
@@ -1,27 +1,24 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
- * Enterprise Fibre Channel Host Bus Adapters.                     *
- * Refer to the README file included with this package for         *
- * driver version and adapter support.                             *
- * Copyright (C) 2004 Emulex Corporation.                          *
+ * Fibre Channel Host Bus Adapters.                                *
+ * Copyright (C) 2004-2005 Emulex.  All rights reserved.           *
+ * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
+ * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
  *                                                                 *
  * This program is free software; you can redistribute it and/or   *
- * modify it under the terms of the GNU General Public License     *
- * as published by the Free Software Foundation; either version 2  *
- * of the License, or (at your option) any later version.          *
- *                                                                 *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of  *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   *
- * GNU General Public License for more details, a copy of which    *
- * can be found in the file COPYING included with this package.    *
+ * modify it under the terms of version 2 of the GNU General       *
+ * Public License as published by the Free Software Foundation.    *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
+ * more details, a copy of which can be found in the file COPYING  *
+ * included with this package.                                     *
  *******************************************************************/
 
-/*
- * $Id: lpfc_scsi.c 1.37 2005/04/13 14:27:09EDT sf_support Exp  $
- */
-
 #include <linux/pci.h>
 #include <linux/interrupt.h>
 
 #define LPFC_RESET_WAIT  2
 #define LPFC_ABORT_WAIT  2
 
-static inline void lpfc_put_lun(struct fcp_cmnd *fcmd, unsigned int lun)
-{
-       fcmd->fcpLunLsl = 0;
-       fcmd->fcpLunMsl = swab16((uint16_t)lun);
-}
 
 /*
  * This routine allocates a scsi buffer, which contains all the necessary
@@ -241,6 +233,8 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd)
                bpl->tus.f.bdeSize = scsi_cmnd->request_bufflen;
                if (datadir == DMA_TO_DEVICE)
                        bpl->tus.f.bdeFlags = 0;
+               else
+                       bpl->tus.f.bdeFlags = BUFF_USE_RCV;
                bpl->tus.w = le32_to_cpu(bpl->tus.w);
                num_bde = 1;
                bpl++;
@@ -248,8 +242,11 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd)
 
        /*
         * Finish initializing those IOCB fields that are dependent on the
-        * scsi_cmnd request_buffer
+        * scsi_cmnd request_buffer.  Note that the bdeSize is explicitly
+        * reinitialized since all iocb memory resources are used many times
+        * for transmit, receive, and continuation bpl's.
         */
+       iocb_cmd->un.fcpi64.bdl.bdeSize = (2 * sizeof (struct ulp_bde64));
        iocb_cmd->un.fcpi64.bdl.bdeSize +=
                (num_bde * sizeof (struct ulp_bde64));
        iocb_cmd->ulpBdeCount = 1;
@@ -406,14 +403,9 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
                        break;
                }
 
-               if (pnode) {
-                       if (pnode->nlp_state != NLP_STE_MAPPED_NODE)
-                               cmd->result = ScsiResult(DID_BUS_BUSY,
-                                       SAM_STAT_BUSY);
-               }
-               else {
-                       cmd->result = ScsiResult(DID_NO_CONNECT, 0);
-               }
+               if ((pnode == NULL )
+                   || (pnode->nlp_state != NLP_STE_MAPPED_NODE))
+                       cmd->result = ScsiResult(DID_BUS_BUSY, SAM_STAT_BUSY);
        } else {
                cmd->result = ScsiResult(DID_OK, 0);
        }
@@ -448,8 +440,11 @@ lpfc_scsi_prep_cmnd(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd,
        int datadir = scsi_cmnd->sc_data_direction;
 
        lpfc_cmd->fcp_rsp->rspSnsLen = 0;
+       /* clear task management bits */
+       lpfc_cmd->fcp_cmnd->fcpCntl2 = 0;
 
-       lpfc_put_lun(lpfc_cmd->fcp_cmnd, lpfc_cmd->pCmd->device->lun);
+       int_to_scsilun(lpfc_cmd->pCmd->device->lun,
+                       &lpfc_cmd->fcp_cmnd->fcp_lun);
 
        memcpy(&fcp_cmnd->fcpCdb[0], scsi_cmnd->cmnd, 16);
 
@@ -539,7 +534,7 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba,
        struct lpfc_rport_data *rdata = scsi_dev->hostdata;
        struct lpfc_nodelist *ndlp = rdata->pnode;
 
-       if ((ndlp == 0) || (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) {
+       if ((ndlp == NULL) || (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) {
                return 0;
        }
 
@@ -548,7 +543,8 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba,
        piocb = &piocbq->iocb;
 
        fcp_cmnd = lpfc_cmd->fcp_cmnd;
-       lpfc_put_lun(lpfc_cmd->fcp_cmnd, lpfc_cmd->pCmd->device->lun);
+       int_to_scsilun(lpfc_cmd->pCmd->device->lun,
+                       &lpfc_cmd->fcp_cmnd->fcp_lun);
        fcp_cmnd->fcpCntl2 = task_mgmt_cmd;
 
        piocb->ulpCommand = CMD_FCP_ICMND64_CR;
@@ -726,35 +722,23 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
        struct lpfc_rport_data *rdata = cmnd->device->hostdata;
        struct lpfc_nodelist *ndlp = rdata->pnode;
        struct lpfc_scsi_buf *lpfc_cmd = NULL;
+       struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
        struct list_head *scsi_buf_list = &phba->lpfc_scsi_buf_list;
-       int err = 0;
+       int err;
 
-       /*
-        * The target pointer is guaranteed not to be NULL because the driver
-        * only clears the device->hostdata field in lpfc_slave_destroy.  This
-        * approach guarantees no further IO calls on this target.
-        */
-       if (!ndlp) {
-               cmnd->result = ScsiResult(DID_NO_CONNECT, 0);
+       err = fc_remote_port_chkready(rport);
+       if (err) {
+               cmnd->result = err;
                goto out_fail_command;
        }
 
        /*
-        * A Fibre Channel target is present and functioning only when the node
-        * state is MAPPED.  Any other state is a failure.
+        * Catch race where our node has transitioned, but the
+        * transport is still transitioning.
         */
-       if (ndlp->nlp_state != NLP_STE_MAPPED_NODE) {
-               if ((ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) ||
-                   (ndlp->nlp_state == NLP_STE_UNUSED_NODE)) {
-                       cmnd->result = ScsiResult(DID_NO_CONNECT, 0);
-                       goto out_fail_command;
-               }
-               /*
-                * The device is most likely recovered and the driver
-                * needs a bit more time to finish.  Ask the midlayer
-                * to retry.
-                */
-               goto out_host_busy;
+       if (!ndlp) {
+               cmnd->result = ScsiResult(DID_BUS_BUSY, 0);
+               goto out_fail_command;
        }
 
        list_remove_head(scsi_buf_list, lpfc_cmd, struct lpfc_scsi_buf, list);
@@ -874,6 +858,7 @@ __lpfc_abort_handler(struct scsi_cmnd *cmnd)
                else
                        icmd->ulpCommand = CMD_CLOSE_XRI_CN;
 
+               abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl;
                if (lpfc_sli_issue_iocb(phba, pring, abtsiocb, 0) ==
                                                                IOCB_ERROR) {
                        list_add_tail(&abtsiocb->list, lpfc_iocb_list);
@@ -1054,7 +1039,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
  * Note: midlayer calls this function with the host_lock held
  */
 static int
-lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
+__lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
 {
        struct Scsi_Host *shost = cmnd->device->host;
        struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata[0];
@@ -1143,48 +1128,30 @@ out:
        return ret;
 }
 
+static int
+lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
+{
+       int rc;
+       spin_lock_irq(cmnd->device->host->host_lock);
+       rc = __lpfc_reset_bus_handler(cmnd);
+       spin_unlock_irq(cmnd->device->host->host_lock);
+       return rc;
+}
+
 static int
 lpfc_slave_alloc(struct scsi_device *sdev)
 {
        struct lpfc_hba *phba = (struct lpfc_hba *)sdev->host->hostdata[0];
-       struct lpfc_nodelist *ndlp = NULL;
-       int match = 0;
        struct lpfc_scsi_buf *scsi_buf = NULL;
+       struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
        uint32_t total = 0, i;
        uint32_t num_to_alloc = 0;
        unsigned long flags;
-       struct list_head *listp;
-       struct list_head *node_list[6];
-
-       /*
-        * Store the target pointer in the scsi_device hostdata pointer provided
-        * the driver has already discovered the target id.
-        */
-
-       /* Search the nlp lists other than unmap_list for this target ID */
-       node_list[0] = &phba->fc_npr_list;
-       node_list[1] = &phba->fc_nlpmap_list;
-       node_list[2] = &phba->fc_prli_list;
-       node_list[3] = &phba->fc_reglogin_list;
-       node_list[4] = &phba->fc_adisc_list;
-       node_list[5] = &phba->fc_plogi_list;
-
-       for (i = 0; i < 6 && !match; i++) {
-               listp = node_list[i];
-               if (list_empty(listp))
-                       continue;
-               list_for_each_entry(ndlp, listp, nlp_listp) {
-                       if ((sdev->id == ndlp->nlp_sid) && ndlp->rport) {
-                               match = 1;
-                               break;
-                       }
-               }
-       }
 
-       if (!match)
+       if (!rport || fc_remote_port_chkready(rport))
                return -ENXIO;
 
-       sdev->hostdata = ndlp->rport->dd_data;
+       sdev->hostdata = rport->dd_data;
 
        /*
         * Populate the cmds_per_lun count scsi_bufs into this host's globally
@@ -1263,4 +1230,5 @@ struct scsi_host_template lpfc_template = {
        .cmd_per_lun            = LPFC_CMD_PER_LUN,
        .use_clustering         = ENABLE_CLUSTERING,
        .shost_attrs            = lpfc_host_attrs,
+       .max_sectors            = 0xFFFF,
 };