Deleted Added
sdiff udiff text old ( 167082 ) new ( 168752 )
full compact
1/*-
2 * Generic SCSI Target Kernel Mode Driver
3 *
4 * Copyright (c) 2002 Nate Lawson.
5 * Copyright (c) 1998, 1999, 2001, 2002 Justin T. Gibbs.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without

--- 14 unchanged lines hidden (view full) ---

23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: head/sys/cam/scsi/scsi_target.c 167082 2007-02-27 17:15:39Z jhb $");
32
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/kernel.h>
37#include <sys/conf.h>
38#include <sys/malloc.h>
39#include <sys/poll.h>
40#include <sys/vnode.h>
41#include <sys/lock.h>
42#include <sys/mutex.h>
43#include <sys/devicestat.h>
44#include <sys/proc.h>
45
46#include <cam/cam.h>
47#include <cam/cam_ccb.h>
48#include <cam/cam_periph.h>
49#include <cam/cam_xpt_periph.h>
50#include <cam/scsi/scsi_targetio.h>
51
52/* Transaction information attached to each CCB sent by the user */
53struct targ_cmd_descr {
54 struct cam_periph_map_info mapinfo;
55 TAILQ_ENTRY(targ_cmd_descr) tqe;
56 union ccb *user_ccb;
57 int priority;

--- 97 unchanged lines hidden (view full) ---

155{
156 targinit, "targ",
157 TAILQ_HEAD_INITIALIZER(targdriver.units), /* generation */ 0
158};
159PERIPHDRIVER_DECLARE(targ, targdriver);
160
161static MALLOC_DEFINE(M_TARG, "TARG", "TARG data");
162
163/* Create softc and initialize it. Only one proc can open each targ device. */
164static int
165targopen(struct cdev *dev, int flags, int fmt, struct thread *td)
166{
167 struct targ_softc *softc;
168
169 if (dev->si_drv1 != 0) {
170 return (EBUSY);
171 }

--- 22 unchanged lines hidden (view full) ---

194 return (0);
195}
196
197/* Disable LUN if enabled and teardown softc */
198static int
199targclose(struct cdev *dev, int flag, int fmt, struct thread *td)
200{
201 struct targ_softc *softc;
202 int error;
203
204 softc = (struct targ_softc *)dev->si_drv1;
205 error = targdisable(softc);
206 if (error == CAM_REQ_CMP) {
207 dev->si_drv1 = 0;
208 if (softc->periph != NULL) {
209 cam_periph_invalidate(softc->periph);
210 softc->periph = NULL;
211 }
212 destroy_dev(dev);
213 FREE(softc, M_TARG);
214 }
215 return (error);
216}
217
218/* Enable/disable LUNs, set debugging level */
219static int
220targioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
221{
222 struct targ_softc *softc;
223 cam_status status;
224
225 softc = (struct targ_softc *)dev->si_drv1;
226
227 switch (cmd) {
228 case TARGIOCENABLE:
229 {
230 struct ioc_enable_lun *new_lun;
231 struct cam_path *path;
232
233 new_lun = (struct ioc_enable_lun *)addr;
234 status = xpt_create_path(&path, /*periph*/NULL,
235 new_lun->path_id,
236 new_lun->target_id,
237 new_lun->lun_id);
238 if (status != CAM_REQ_CMP) {
239 printf("Couldn't create path, status %#x\n", status);
240 break;
241 }
242 status = targenable(softc, path, new_lun->grp6_len,
243 new_lun->grp7_len);
244 xpt_free_path(path);
245 break;
246 }
247 case TARGIOCDISABLE:
248 status = targdisable(softc);
249 break;
250 case TARGIOCDEBUG:
251 {
252#ifdef CAMDEBUG
253 struct ccb_debug cdbg;
254
255 bzero(&cdbg, sizeof cdbg);
256 if (*((int *)addr) != 0)
257 cdbg.flags = CAM_DEBUG_PERIPH;
258 else
259 cdbg.flags = CAM_DEBUG_NONE;
260 xpt_setup_ccb(&cdbg.ccb_h, softc->path, /*priority*/0);
261 cdbg.ccb_h.func_code = XPT_DEBUG;
262 cdbg.ccb_h.cbfcnp = targdone;
263
264 /* If no periph available, disallow debugging changes */
265 if ((softc->state & TARG_STATE_LUN_ENABLED) == 0) {
266 status = CAM_DEV_NOT_THERE;
267 break;
268 }
269 xpt_action((union ccb *)&cdbg);
270 status = cdbg.ccb_h.status & CAM_STATUS_MASK;
271#else
272 status = CAM_FUNC_NOTAVAIL;
273#endif
274 break;
275 }
276 default:
277 status = CAM_PROVIDE_FAIL;

--- 11 unchanged lines hidden (view full) ---

289 int revents;
290
291 softc = (struct targ_softc *)dev->si_drv1;
292
293 /* Poll for write() is always ok. */
294 revents = poll_events & (POLLOUT | POLLWRNORM);
295 if ((poll_events & (POLLIN | POLLRDNORM)) != 0) {
296 /* Poll for read() depends on user and abort queues. */
297 if (!TAILQ_EMPTY(&softc->user_ccb_queue) ||
298 !TAILQ_EMPTY(&softc->abort_queue)) {
299 revents |= poll_events & (POLLIN | POLLRDNORM);
300 }
301 /* Only sleep if the user didn't poll for write. */
302 if (revents == 0)
303 selrecord(td, &softc->read_select);
304 }
305
306 return (revents);
307}
308

--- 21 unchanged lines hidden (view full) ---

330/* Notify the user's kqueue when the user queue or abort queue gets a CCB */
331static int
332targreadfilt(struct knote *kn, long hint)
333{
334 struct targ_softc *softc;
335 int retval;
336
337 softc = (struct targ_softc *)kn->kn_hook;
338 retval = !TAILQ_EMPTY(&softc->user_ccb_queue) ||
339 !TAILQ_EMPTY(&softc->abort_queue);
340 return (retval);
341}
342
343/* Send the HBA the enable/disable message */
344static cam_status
345targendislun(struct cam_path *path, int enable, int grp6_len, int grp7_len)
346{
347 struct ccb_en_lun en_ccb;

--- 179 unchanged lines hidden (view full) ---

527 if (priority == -1) {
528 error = EINVAL;
529 break;
530 }
531 func_code = fuword32(&user_ccb->ccb_h.func_code);
532 switch (func_code) {
533 case XPT_ACCEPT_TARGET_IO:
534 case XPT_IMMED_NOTIFY:
535 ccb = targgetccb(softc, func_code, priority);
536 descr = (struct targ_cmd_descr *)ccb->ccb_h.targ_descr;
537 descr->user_ccb = user_ccb;
538 descr->func_code = func_code;
539 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
540 ("Sent ATIO/INOT (%p)\n", user_ccb));
541 xpt_action(ccb);
542 TAILQ_INSERT_TAIL(&softc->pending_ccb_queue,
543 &ccb->ccb_h,
544 periph_links.tqe);
545 break;
546 default:
547 if ((func_code & XPT_FC_QUEUED) != 0) {
548 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
549 ("Sending queued ccb %#x (%p)\n",
550 func_code, user_ccb));
551 descr = targgetdescr(softc);
552 descr->user_ccb = user_ccb;
553 descr->priority = priority;
554 descr->func_code = func_code;

--- 9 unchanged lines hidden (view full) ---

564 ccb->ccb_h.targ_descr;
565 descr->user_ccb = user_ccb;
566 descr->priority = priority;
567 descr->func_code = func_code;
568 if (targusermerge(softc, descr, ccb) != EFAULT)
569 targsendccb(softc, ccb, descr);
570 targreturnccb(softc, ccb);
571 }
572 break;
573 }
574 write_len += sizeof(user_ccb);
575 }
576
577 /*
578 * If we've successfully taken in some amount of
579 * data, return success for that data first. If

--- 211 unchanged lines hidden (view full) ---

791 struct descr_queue *abort_queue;
792 struct targ_cmd_descr *user_descr;
793 struct targ_softc *softc;
794 struct ccb_queue *user_queue;
795 struct ccb_hdr *ccb_h;
796 union ccb *user_ccb;
797 int read_len, error;
798
799 mtx_lock(&Giant);
800
801 error = 0;
802 read_len = 0;
803 softc = (struct targ_softc *)dev->si_drv1;
804 user_queue = &softc->user_ccb_queue;
805 abort_queue = &softc->abort_queue;
806 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targread\n"));
807
808 /* If no data is available, wait or return immediately */
809 ccb_h = TAILQ_FIRST(user_queue);
810 user_descr = TAILQ_FIRST(abort_queue);
811 while (ccb_h == NULL && user_descr == NULL) {
812 if ((ioflag & IO_NDELAY) == 0) {
813 error = tsleep(user_queue,
814 PRIBIO | PCATCH, "targrd", 0);
815 ccb_h = TAILQ_FIRST(user_queue);
816 user_descr = TAILQ_FIRST(abort_queue);
817 if (error != 0) {
818 if (error == ERESTART) {
819 continue;
820 } else {
821 goto read_fail;
822 }
823 }
824 } else {
825 mtx_unlock(&Giant);
826 return (EAGAIN);
827 }
828 }
829
830 /* Data is available so fill the user's buffer */
831 while (ccb_h != NULL) {
832 struct targ_cmd_descr *descr;
833
834 if (uio->uio_resid < sizeof(user_ccb))
835 break;
836 TAILQ_REMOVE(user_queue, ccb_h, periph_links.tqe);
837 descr = (struct targ_cmd_descr *)ccb_h->targ_descr;
838 user_ccb = descr->user_ccb;
839 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
840 ("targread ccb %p (%p)\n", ccb_h, user_ccb));
841 error = targreturnccb(softc, (union ccb *)ccb_h);
842 if (error != 0)
843 goto read_fail;
844 error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio);
845 if (error != 0)
846 goto read_fail;
847 read_len += sizeof(user_ccb);
848
849 ccb_h = TAILQ_FIRST(user_queue);
850 }
851
852 /* Flush out any aborted descriptors */
853 while (user_descr != NULL) {
854 if (uio->uio_resid < sizeof(user_ccb))
855 break;
856 TAILQ_REMOVE(abort_queue, user_descr, tqe);
857 user_ccb = user_descr->user_ccb;
858 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
859 ("targread aborted descr %p (%p)\n",
860 user_descr, user_ccb));
861 suword(&user_ccb->ccb_h.status, CAM_REQ_ABORTED);
862 error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio);
863 if (error != 0)
864 goto read_fail;
865 read_len += sizeof(user_ccb);
866
867 user_descr = TAILQ_FIRST(abort_queue);
868 }
869
870 /*
871 * If we've successfully read some amount of data, don't report an
872 * error. If the error is persistent, it will be reported on the
873 * next read().
874 */
875 if (read_len == 0 && uio->uio_resid != 0)
876 error = ENOSPC;
877
878read_fail:
879 mtx_unlock(&Giant);
880 return (error);
881}
882
883/* Copy completed ccb back to the user */
884static int
885targreturnccb(struct targ_softc *softc, union ccb *ccb)
886{
887 struct targ_cmd_descr *descr;

--- 112 unchanged lines hidden (view full) ---

1000
1001/* Cancel all pending requests and CCBs awaiting work. */
1002static void
1003abort_all_pending(struct targ_softc *softc)
1004{
1005 struct targ_cmd_descr *descr;
1006 struct ccb_abort cab;
1007 struct ccb_hdr *ccb_h;
1008
1009 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("abort_all_pending\n"));
1010
1011 /* First abort the descriptors awaiting resources */
1012 while ((descr = TAILQ_FIRST(&softc->work_queue)) != NULL) {
1013 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
1014 ("Aborting descr from workq %p\n", descr));
1015 TAILQ_REMOVE(&softc->work_queue, descr, tqe);

--- 16 unchanged lines hidden (view full) ---

1032 xpt_print(cab.ccb_h.path,
1033 "Unable to abort CCB, status %#x\n",
1034 cab.ccb_h.status);
1035 }
1036 }
1037
1038 /* If we aborted at least one pending CCB ok, wait for it. */
1039 if (cab.ccb_h.status == CAM_REQ_CMP) {
1040 tsleep(&softc->pending_ccb_queue,
1041 PRIBIO | PCATCH, "tgabrt", 0);
1042 }
1043
1044 /* If we aborted anything from the work queue, wakeup user. */
1045 if (!TAILQ_EMPTY(&softc->user_ccb_queue)
1046 || !TAILQ_EMPTY(&softc->abort_queue))
1047 notify_user(softc);
1048}

--- 91 unchanged lines hidden ---